""" pixtosky - A module to perform coordinate transformation from pixel coordinates
                in one image to pixel coordinates in another frame

    :Authors: <NAME>

    :License: :doc:`LICENSE`

    PARAMETERS
    ----------
    inimage : str
        full filename with path of input image, an extension name ['sci',1] should be
        provided if input is a multi-extension FITS file
    outimage : str, optional
        full filename with path of output image, an extension name ['sci',1] should be
        provided if output is a multi-extension FITS file. If no image gets
        specified, the input image will be used to generate a default output
        WCS using stwcs.distortion.util.output_wcs().
    direction : str
        Direction of transform (forward or backward). The 'forward' transform
        takes the pixel positions (assumed to be from the 'input' image) and determines
        their position in the 'output' image. The 'backward' transform converts
        the pixel positions (assumed to be from the 'output' image) into pixel
        positions in the 'input' image.


    Optional Parameters
    -------------------
    x : float, optional
        X position from image
    y : float, optional
        Y position from image
    coords : str, deprecated
        [DEPRECATED] full filename with path of file with x,y coordinates
        Filename given here will be *ignored* if a file has been specified
        in `coordfile` parameter.
    coordfile : str, optional
        full filename with path of file with starting x,y coordinates
    colnames : str, optional
        comma separated list of column names from 'coordfile' files
        containing x,y coordinates, respectively. Will default to
        first two columns if None are specified. Column names for ASCII
        files will use 'c1','c2',... convention.
    separator : str, optional
        non-blank separator used as the column delimiter in the coordfile file
    precision : int, optional
        Number of floating-point digits in output values
    output : str, optional
        Name of output file with results, if desired
    verbose : bool
        Print out full list of transformation results (default: False)

    RETURNS
    -------
    outx : float
        X position of transformed pixel. If more than 1 input value, then it
        will be a numpy array.
    outy : float
        Y position of transformed pixel. If more than 1 input value, then it
        will be a numpy array.

    NOTES
    -----
    This module performs a full distortion-corrected coordinate transformation
    based on all WCS keywords and any recognized distortion keywords from the
    input image header.

    Usage
    -----
    It can be called from within Python using the syntax::

        >>> from drizzlepac import pixtopix
        >>> outx,outy = pixtopix.tran("input_flt.fits[sci,1]",
                        "output_drz.fits[sci,1],"forward",100,100)

    EXAMPLES
    --------

    1. The following command will transform the position 256,256 from
        'input_flt.fits[sci,1]' into a position on the output image
        'output_drz.fits[sci,1]' using::

            >>> from drizzlepac import pixtopix
            >>> outx,outy = pixtopix.tran("input_file_flt.fits[sci,1]",
                        "output_drz.fits[sci,1],"forward", 256,256)


    2. The set of X,Y positions from 'output_drz.fits[sci,1]' stored as
        the 3rd and 4th columns from the ASCII file 'xy_sci1.dat'
        will be transformed into pixel positions from 'input_flt.fits[sci,1]'
        and written out to 'xy_flt1.dat' using::

            >>> from drizzlepac import pixtopix
            >>> x,y = pixtopix.tran("input_flt.fits[sci,1]", "output_drz.fits[sci,1]",
                    "backward", coordfile='xy_sci1.dat', colnames=['c3','c4'],
                    output="xy_flt1.dat")

"""
from __future__ import absolute_import, division, print_function # confidence medium

import os,copy
import warnings
import numpy as np

from stsci.tools import fileutil, teal
from . import wcs_functions
from . import util
from stwcs import wcsutil, distortion

# This is specifically NOT intended to match the package-wide version information.
__version__ = '0.1'
__version_date__ = '1-Mar-2011'

__taskname__ = 'pixtopix'

def tran(inimage,outimage,direction='forward',x=None,y=None,
        coords=None, coordfile=None,colnames=None,separator=None,
        precision=6, output=None,verbose=True):
    """ Primary interface to perform coordinate transformations in pixel
        coordinates between 2 images using STWCS and full distortion models
        read from each image's header.
    """
    single_coord = False

    # Only use value provided in `coords` if nothing has been specified for coordfile
    if coords is not None and coordfile is None:
        coordfile = coords
        warnings.simplefilter('always',DeprecationWarning)
        warnings.warn("Please update calling code to pass in `coordfile` instead of `coords`.",
            category=DeprecationWarning)
        warnings.simplefilter('default',DeprecationWarning)

    if coordfile is not None:
        if colnames in util.blank_list:
            colnames = ['c1','c2']
        # Determine columns which contain pixel positions
        cols = util.parse_colnames(colnames,coordfile)
        # read in columns from input coordinates file
        xyvals = np.loadtxt(coordfile,usecols=cols,delimiter=separator)
        if xyvals.ndim == 1: # only 1 entry in coordfile
            xlist = [xyvals[0].copy()]
            ylist = [xyvals[1].copy()]
        else:
            xlist = xyvals[:,0].copy()
            ylist = xyvals[:,1].copy()
        del xyvals
    else:
        if isinstance(x,np.ndarray):
            xlist = x.tolist()
            ylist = y.tolist()
        elif not isinstance(x,list):
            xlist = [x]
            ylist = [y]
            single_coord = True
        else:
            xlist = x
            ylist = y

    # start by reading in WCS+distortion info for each image
    im1wcs = wcsutil.HSTWCS(inimage)
    if im1wcs.wcs.is_unity():
        print("####\nNo valid input WCS found in {}.\n  Results may be invalid.\n####\n".format(inimage))

    if util.is_blank(outimage):
        fname,fextn = fileutil.parseFilename(inimage)
        numsci = fileutil.countExtn(fname)
        chips = []
        for e in range(1,numsci+1):
            chips.append(wcsutil.HSTWCS(fname,ext=('sci',e)))
        if len(chips) == 0:
            chips = [im1wcs]
        im2wcs = distortion.utils.output_wcs(chips)
    else:
        im2wcs = wcsutil.HSTWCS(outimage)

    if im2wcs.wcs.is_unity():
        print("####\nNo valid output WCS found in {}.\n  Results may be invalid.\n####\n".format(outimage))

    # Setup the transformation
    p2p = wcs_functions.WCSMap(im1wcs,im2wcs)

    if direction[0].lower() == 'f':
        outx,outy = p2p.forward(xlist,ylist)
    else:
        outx,outy = p2p.backward(xlist,ylist)

    if isinstance(outx,np.ndarray):
        outx = outx.tolist()
        outy = outy.tolist()

    # add formatting based on precision here...
    xstr = []
    ystr = []
    fmt = "%."+repr(precision)+"f"
    for ox,oy in zip(outx,outy):
        xstr.append(fmt%ox)
        ystr.append(fmt%oy)

    if verbose or (not verbose and util.is_blank(output)):
        print('# Coordinate transformations for ',inimage)
        print('# X(in)      Y(in)             X(out)         Y(out)\n')
        for xs,ys,a,b in zip(xlist,ylist,xstr,ystr):
            print("%.4f  %.4f    %s  %s"%(xs,ys,a,b))

    # Create output file, if specified
    if output:
        f = open(output,mode='w')
        f.write("# Coordinates converted from %s\n"%inimage)
        for xs,ys in zip(xstr,ystr):
            f.write('%s    %s\n'%(xs,ys))
        f.close()
        print('Wrote out results to: ',output)

    if single_coord:
        outx = outx[0]
        outy = outy[0]
    return outx,outy


#--------------------------
# TEAL Interface functions
#--------------------------
def run(configObj):

    if 'coords' in configObj:
        coords = util.check_blank(configObj['coords'])
    else:
        coords = None

    coordfile = util.check_blank(configObj['coordfile'])
    colnames = util.check_blank(configObj['colnames'])
    sep = util.check_blank(configObj['separator'])
    outfile = util.check_blank(configObj['output'])

    outimage = util.check_blank(configObj['outimage'])
    tran(configObj['inimage'], outimage,direction=configObj['direction'],
            x = configObj['x'], y = configObj['y'], coords=coords,
            coordfile = coordfile, colnames = colnames,
            separator= sep, precision= configObj['precision'],
            output= outfile, verbose = configObj['verbose'])


def help(file=None):
    """
    Print out syntax help for running astrodrizzle

    Parameters
    ----------
    file : str (Default = None)
        If given, write out help to the filename specified by this parameter
        Any previously existing file with this name will be deleted before
        writing out the help.

    """
    helpstr = getHelpAsString(docstring=True, show_ver = True)
    if file is None:
        print(helpstr)
    else:
        if os.path.exists(file): os.remove(file)
        f = open(file, mode = 'w')
        f.write(helpstr)
        f.close()


def getHelpAsString(docstring = False, show_ver = True):
    """
    return useful help from a file in the script directory called
    __taskname__.help

    """
    install_dir = os.path.dirname(__file__)
    taskname = util.base_taskname(__taskname__, '')
    htmlfile = os.path.join(install_dir, 'htmlhelp', taskname + '.html')
    helpfile = os.path.join(install_dir, taskname + '.help')

    if docstring or (not docstring and not os.path.exists(htmlfile)):
        if show_ver:
            helpString = os.linesep + \
                ' '.join([__taskname__, 'Version', __version__,
                ' updated on ', __version_date__]) + 2*os.linesep
        else:
            helpString = ''
        if os.path.exists(helpfile):
            helpString += teal.getHelpFileAsString(taskname, __file__)
        else:
            if __doc__ is not None:
                helpString += __doc__ + os.linesep
    else:
        helpString = 'file://' + htmlfile

    return helpString

__doc__ = getHelpAsString(docstring = True, show_ver = False)

""" pixtosky - A module to perform coordinate transformation from pixel coordinates
                in one image to pixel coordinates in another frame

    :Authors: <NAME>

    :License: :doc:`LICENSE`

    PARAMETERS
    ----------
    inimage : str
        full filename with path of input image, an extension name ['sci',1] should be
        provided if input is a multi-extension FITS file
    outimage : str, optional
        full filename with path of output image, an extension name ['sci',1] should be
        provided if output is a multi-extension FITS file. If no image gets
        specified, the input image will be used to generate a default output
        WCS using stwcs.distortion.util.output_wcs().
    direction : str
        Direction of transform (forward or backward). The 'forward' transform
        takes the pixel positions (assumed to be from the 'input' image) and determines
        their position in the 'output' image. The 'backward' transform converts
        the pixel positions (assumed to be from the 'output' image) into pixel
        positions in the 'input' image.


    Optional Parameters
    -------------------
    x : float, optional
        X position from image
    y : float, optional
        Y position from image
    coords : str, deprecated
        [DEPRECATED] full filename with path of file with x,y coordinates
        Filename given here will be *ignored* if a file has been specified
        in `coordfile` parameter.
    coordfile : str, optional
        full filename with path of file with starting x,y coordinates
    colnames : str, optional
        comma separated list of column names from 'coordfile' files
        containing x,y coordinates, respectively. Will default to
        first two columns if None are specified. Column names for ASCII
        files will use 'c1','c2',... convention.
    separator : str, optional
        non-blank separator used as the column delimiter in the coordfile file
    precision : int, optional
        Number of floating-point digits in output values
    output : str, optional
        Name of output file with results, if desired
    verbose : bool
        Print out full list of transformation results (default: False)

    RETURNS
    -------
    outx : float
        X position of transformed pixel. If more than 1 input value, then it
        will be a numpy array.
    outy : float
        Y position of transformed pixel. If more than 1 input value, then it
        will be a numpy array.

    NOTES
    -----
    This module performs a full distortion-corrected coordinate transformation
    based on all WCS keywords and any recognized distortion keywords from the
    input image header.

    Usage
    -----
    It can be called from within Python using the syntax::

        >>> from drizzlepac import pixtopix
        >>> outx,outy = pixtopix.tran("input_flt.fits[sci,1]",
                        "output_drz.fits[sci,1],"forward",100,100)

    EXAMPLES
    --------

    1. The following command will transform the position 256,256 from
        'input_flt.fits[sci,1]' into a position on the output image
        'output_drz.fits[sci,1]' using::

            >>> from drizzlepac import pixtopix
            >>> outx,outy = pixtopix.tran("input_file_flt.fits[sci,1]",
                        "output_drz.fits[sci,1],"forward", 256,256)


    2. The set of X,Y positions from 'output_drz.fits[sci,1]' stored as
        the 3rd and 4th columns from the ASCII file 'xy_sci1.dat'
        will be transformed into pixel positions from 'input_flt.fits[sci,1]'
        and written out to 'xy_flt1.dat' using::

            >>> from drizzlepac import pixtopix
            >>> x,y = pixtopix.tran("input_flt.fits[sci,1]", "output_drz.fits[sci,1]",
                    "backward", coordfile='xy_sci1.dat', colnames=['c3','c4'],
                    output="xy_flt1.dat")

"""
from __future__ import absolute_import, division, print_function # confidence medium

import os,copy
import warnings
import numpy as np

from stsci.tools import fileutil, teal
from . import wcs_functions
from . import util
from stwcs import wcsutil, distortion

# This is specifically NOT intended to match the package-wide version information.
__version__ = '0.1'
__version_date__ = '1-Mar-2011'

__taskname__ = 'pixtopix'

def tran(inimage,outimage,direction='forward',x=None,y=None,
        coords=None, coordfile=None,colnames=None,separator=None,
        precision=6, output=None,verbose=True):
    """ Primary interface to perform coordinate transformations in pixel
        coordinates between 2 images using STWCS and full distortion models
        read from each image's header.
    """
    single_coord = False

    # Only use value provided in `coords` if nothing has been specified for coordfile
    if coords is not None and coordfile is None:
        coordfile = coords
        warnings.simplefilter('always',DeprecationWarning)
        warnings.warn("Please update calling code to pass in `coordfile` instead of `coords`.",
            category=DeprecationWarning)
        warnings.simplefilter('default',DeprecationWarning)

    if coordfile is not None:
        if colnames in util.blank_list:
            colnames = ['c1','c2']
        # Determine columns which contain pixel positions
        cols = util.parse_colnames(colnames,coordfile)
        # read in columns from input coordinates file
        xyvals = np.loadtxt(coordfile,usecols=cols,delimiter=separator)
        if xyvals.ndim == 1: # only 1 entry in coordfile
            xlist = [xyvals[0].copy()]
            ylist = [xyvals[1].copy()]
        else:
            xlist = xyvals[:,0].copy()
            ylist = xyvals[:,1].copy()
        del xyvals
    else:
        if isinstance(x,np.ndarray):
            xlist = x.tolist()
            ylist = y.tolist()
        elif not isinstance(x,list):
            xlist = [x]
            ylist = [y]
            single_coord = True
        else:
            xlist = x
            ylist = y

    # start by reading in WCS+distortion info for each image
    im1wcs = wcsutil.HSTWCS(inimage)
    if im1wcs.wcs.is_unity():
        print("####\nNo valid input WCS found in {}.\n  Results may be invalid.\n####\n".format(inimage))

    if util.is_blank(outimage):
        fname,fextn = fileutil.parseFilename(inimage)
        numsci = fileutil.countExtn(fname)
        chips = []
        for e in range(1,numsci+1):
            chips.append(wcsutil.HSTWCS(fname,ext=('sci',e)))
        if len(chips) == 0:
            chips = [im1wcs]
        im2wcs = distortion.utils.output_wcs(chips)
    else:
        im2wcs = wcsutil.HSTWCS(outimage)

    if im2wcs.wcs.is_unity():
        print("####\nNo valid output WCS found in {}.\n  Results may be invalid.\n####\n".format(outimage))

    # Setup the transformation
    p2p = wcs_functions.WCSMap(im1wcs,im2wcs)

    if direction[0].lower() == 'f':
        outx,outy = p2p.forward(xlist,ylist)
    else:
        outx,outy = p2p.backward(xlist,ylist)

    if isinstance(outx,np.ndarray):
        outx = outx.tolist()
        outy = outy.tolist()

    # add formatting based on precision here...
    xstr = []
    ystr = []
    fmt = "%."+repr(precision)+"f"
    for ox,oy in zip(outx,outy):
        xstr.append(fmt%ox)
        ystr.append(fmt%oy)

    if verbose or (not verbose and util.is_blank(output)):
        print('# Coordinate transformations for ',inimage)
        print('# X(in)      Y(in)             X(out)         Y(out)\n')
        for xs,ys,a,b in zip(xlist,ylist,xstr,ystr):
            print("%.4f  %.4f    %s  %s"%(xs,ys,a,b))

    # Create output file, if specified
    if output:
        f = open(output,mode='w')
        f.write("# Coordinates converted from %s\n"%inimage)
        for xs,ys in zip(xstr,ystr):
            f.write('%s    %s\n'%(xs,ys))
        f.close()
        print('Wrote out results to: ',output)

    if single_coord:
        outx = outx[0]
        outy = outy[0]
    return outx,outy


#--------------------------
# TEAL Interface functions
#--------------------------
def run(configObj):

    if 'coords' in configObj:
        coords = util.check_blank(configObj['coords'])
    else:
        coords = None

    coordfile = util.check_blank(configObj['coordfile'])
    colnames = util.check_blank(configObj['colnames'])
    sep = util.check_blank(configObj['separator'])
    outfile = util.check_blank(configObj['output'])

    outimage = util.check_blank(configObj['outimage'])
    tran(configObj['inimage'], outimage,direction=configObj['direction'],
            x = configObj['x'], y = configObj['y'], coords=coords,
            coordfile = coordfile, colnames = colnames,
            separator= sep, precision= configObj['precision'],
            output= outfile, verbose = configObj['verbose'])


def help(file=None):
    """
    Print out syntax help for running astrodrizzle

    Parameters
    ----------
    file : str (Default = None)
        If given, write out help to the filename specified by this parameter
        Any previously existing file with this name will be deleted before
        writing out the help.

    """
    helpstr = getHelpAsString(docstring=True, show_ver = True)
    if file is None:
        print(helpstr)
    else:
        if os.path.exists(file): os.remove(file)
        f = open(file, mode = 'w')
        f.write(helpstr)
        f.close()


def getHelpAsString(docstring = False, show_ver = True):
    """
    return useful help from a file in the script directory called
    __taskname__.help

    """
    install_dir = os.path.dirname(__file__)
    taskname = util.base_taskname(__taskname__, '')
    htmlfile = os.path.join(install_dir, 'htmlhelp', taskname + '.html')
    helpfile = os.path.join(install_dir, taskname + '.help')

    if docstring or (not docstring and not os.path.exists(htmlfile)):
        if show_ver:
            helpString = os.linesep + \
                ' '.join([__taskname__, 'Version', __version__,
                ' updated on ', __version_date__]) + 2*os.linesep
        else:
            helpString = ''
        if os.path.exists(helpfile):
            helpString += teal.getHelpFileAsString(taskname, __file__)
        else:
            if __doc__ is not None:
                helpString += __doc__ + os.linesep
    else:
        helpString = 'file://' + htmlfile

    return helpString

__doc__ = getHelpAsString(docstring = True, show_ver = False)

pixtosky - A module to perform coordinate transformation from pixel coordinates                 in one image to pixel coordinates in another frame      :Authors: <NAME>      :License: :doc:`LICENSE`      PARAMETERS     ----------     inimage : str         full filename with path of input image, an extension name ['sci',1] should be         provided if input is a multi-extension FITS file     outimage : str, optional         full filename with path of output image, an extension name ['sci',1] should be         provided if output is a multi-extension FITS file. If no image gets         specified, the input image will be used to generate a default output         WCS using stwcs.distortion.util.output_wcs().     direction : str         Direction of transform (forward or backward). The 'forward' transform         takes the pixel positions (assumed to be from the 'input' image) and determines         their position in the 'output' image. The 'backward' transform converts         the pixel positions (assumed to be from the 'output' image) into pixel         positions in the 'input' image.       Optional Parameters     -------------------     x : float, optional         X position from image     y : float, optional         Y position from image     coords : str, deprecated         [DEPRECATED] full filename with path of file with x,y coordinates         Filename given here will be *ignored* if a file has been specified         in `coordfile` parameter.     coordfile : str, optional         full filename with path of file with starting x,y coordinates     colnames : str, optional         comma separated list of column names from 'coordfile' files         containing x,y coordinates, respectively. Will default to         first two columns if None are specified. Column names for ASCII         files will use 'c1','c2',... convention.     separator : str, optional         non-blank separator used as the column delimiter in the coordfile file     precision : int, optional         Number of floating-point digits in output values     output : str, optional         Name of output file with results, if desired     verbose : bool         Print out full list of transformation results (default: False)      RETURNS     -------     outx : float         X position of transformed pixel. If more than 1 input value, then it         will be a numpy array.     outy : float         Y position of transformed pixel. If more than 1 input value, then it         will be a numpy array.      NOTES     -----     This module performs a full distortion-corrected coordinate transformation     based on all WCS keywords and any recognized distortion keywords from the     input image header.      Usage     -----     It can be called from within Python using the syntax::          >>> from drizzlepac import pixtopix         >>> outx,outy = pixtopix.tran("input_flt.fits[sci,1]",                         "output_drz.fits[sci,1],"forward",100,100)      EXAMPLES     --------      1. The following command will transform the position 256,256 from         'input_flt.fits[sci,1]' into a position on the output image         'output_drz.fits[sci,1]' using::              >>> from drizzlepac import pixtopix             >>> outx,outy = pixtopix.tran("input_file_flt.fits[sci,1]",                         "output_drz.fits[sci,1],"forward", 256,256)       2. The set of X,Y positions from 'output_drz.fits[sci,1]' stored as         the 3rd and 4th columns from the ASCII file 'xy_sci1.dat'         will be transformed into pixel positions from 'input_flt.fits[sci,1]'         and written out to 'xy_flt1.dat' using::              >>> from drizzlepac import pixtopix             >>> x,y = pixtopix.tran("input_flt.fits[sci,1]", "output_drz.fits[sci,1]",                     "backward", coordfile='xy_sci1.dat', colnames=['c3','c4'],                     output="xy_flt1.dat") # confidence medium # This is specifically NOT intended to match the package-wide version information. Primary interface to perform coordinate transformations in pixel         coordinates between 2 images using STWCS and full distortion models         read from each image's header. # Only use value provided in `coords` if nothing has been specified for coordfile # Determine columns which contain pixel positions # read in columns from input coordinates file # only 1 entry in coordfile # start by reading in WCS+distortion info for each image ###\nNo valid input WCS found in {}.\n  Results may be invalid.\n####\n".format(inimage)) ###\nNo valid output WCS found in {}.\n  Results may be invalid.\n####\n".format(outimage)) # Setup the transformation # add formatting based on precision here... # Create output file, if specified #-------------------------- # TEAL Interface functions #-------------------------- Print out syntax help for running astrodrizzle      Parameters     ----------     file : str (Default = None)         If given, write out help to the filename specified by this parameter         Any previously existing file with this name will be deleted before         writing out the help. return useful help from a file in the script directory called     __taskname__.help