# lid.py -- Identity lines in the current spectra
#
# This file is part of Weeds.

import sys
from sicparse import OptionParser
import pyclass
import copy
import linedb
from linedb.consts import *

def drawline(line,xval,band,angle,color):
    """
    Mark the frequency of a line on a spectra

    This function draw the a vertical line at the frequency of the
    line and label it with the species name. The upper axis units of
    the spectra may be either frequency or image. If units are
    frequency the signal frequency will be marked, otherwise the
    signal frequency will be marked. For efficiency reasons, no check
    on the units is done.

    Arguments:
    line  -- a line instance
    xval  -- position on the upper X axis
    band  -- line from SIGNAL or IMAGE band
    angle -- modify the label angle

    """

    # Some databases returns species names in Unicode format:
    if (sys.version_info[0] < 3):
        # Under Python 2 we must convert it to plain ascii
        label = line.species.encode("ascii", "ignore")
    else:
        # Strings under Python 3 are Unicode: leave as is. Just hope
        # the characters are representable in the ASCII set so that
        # Greg can draw them.
        label = line.species
    #
    #
    if color != "*":
        pyclass.comm("pen /col %s" % (color,) )
    elif band == "I":
        pyclass.comm("pen /col green")
    else:
        pyclass.comm("pen /col red")

    pyclass.comm("draw upper %s \"%s\" %s" % (xval, label, angle))
    pyclass.comm("pen /col foreground")


def select_lines(fmin,fmax,species,Eu_max,Aul_min,image,threshold,angle,color):
    #
    # Search for the lines in the given frequency interval using the
    # database, print them in the terminal and mark them on the
    # screen.
    #
    try:
        lines = linedb.select("LID", fmin, fmax, species, 'All', 'All', Eu_max,
                              Aul_min, sortby=['frequency'])
    except NameError:
        pyclass.message(pyclass.seve.e, "LID", "No database selected.")
        pyclass.sicerror()
        return
    except Exception as error:
        pyclass.message(pyclass.seve.e, "LID", "{0}".format(error))
        pyclass.sicerror()
        return

    if (len(lines)==0):
        # linedb.select() has already issued a warning
        return

    # Set upper axis to frequency or image and select pen 1 (signal)
    # or 2 (image)
    units = [u for u in pyclass.gdict.set.las.unit]  # Upper and lower axis units
    old_units = copy.copy(units)
    upperx = units[1]
    if image:
        band = "I"
    else:
        band = "F"

    # Build a subset of lines, to be displayed by LINEDB
    selected = []
    for l in lines:
        # Compute abscissa on the upper X axis
        freq = l.frequency
        xval = pyclass.rx_val(freq,band,upperx)
        #
        drawline_flag = True
        # Threshold on Y-value
        if threshold != -1000:
            # Convert 'freq' to channels:
            cval = pyclass.rx_val(freq,band,'C')
            ci = int(round(cval))
            yi = pyclass.gdict.ry[ci]
            if yi < threshold:
                drawline_flag = False
        if drawline_flag:
            selected.append(l)
            drawline(l,xval,band,angle,color)

    # Let LINEDB do the display:
    if len(selected) == 0:
        pyclass.message(pyclass.seve.w, "LID", "Nothing found")
    else:
        linedb.llist(selected)


def main():
    """
    Extract lines from the spectral line database in the frequency
    range of the current spectra and plot them

    """

    # Parse arguments and options

    parser = OptionParser()
    parser.add_option( "-s", "--species", dest="species", nargs=-1, default=[],
            help="species name [default: %default]")  # nargs -1 for variable number of arguments
    parser.add_option( "-e", "--energy", dest="eu_max", nargs=1, type="float", default = -1,
            help="maximal energy [default: %default]")
    parser.add_option( "-a", "--aij", dest="aij_min", nargs=1, type="float")
    parser.add_option( "-d", "--delta", dest="delta", nargs=1, type="float",
                                       default = 0., help="frequency delta [default: %default]")
    parser.add_option( "-f", "--full",  dest="full",  action="store_true", default = False)
    parser.add_option( "-i", "--image", dest="image", action="store_true", default = False)
    parser.add_option( "-c", "--clip", dest="threshold",nargs=1,
                                       type="float",help="Clip above threshold",default = -1000.)
    parser.add_option( "-g", "--angle", dest="angle", nargs=1, type="float", default = 90.)
    parser.add_option( "-l", "--loop",  dest="loop",  action="store_true", default = False)
    parser.add_option( "-k", "--color", dest="color", nargs=1, default = "*")

    try:
        (options,args) = parser.parse_args()
    except:
        pyclass.message(pyclass.seve.e, "LID", "Invalid option")
        pyclass.sicerror()
        return

    species = options.species
    Eu_max = options.eu_max
    Aij_min = options.aij_min
    delta_freq = abs(options.delta)
    full       = options.full
    threshold  = options.threshold
    image     = options.image
    angle     = options.angle
    loop = options.loop
    color = options.color

    # Import Gildas variables if not yet done:
    if (not pyclass.gotgdict()):
        pyclass.get(verbose=False)

    if (not pyclass.ingdict('rx')):
        pyclass.message(pyclass.seve.e, "LID", "No R spectrum in memory")
        pyclass.sicerror()
        return

    # Import a few variables from Class
    frequency = pyclass.gdict.frequency
    image_frequency = pyclass.gdict.image
    freq_step = pyclass.gdict.freq_step
    use_curs  = pyclass.gdict.use_curs        # Cursor position in user coordinates
    units    = [u for u in pyclass.gdict.set.las.unit]  # Upper and lower axis units

    # Default interval for line id is 10 channels
    if (delta_freq==0.):
        delta_freq = abs(5.*freq_step)

    if full:
        if (loop):
            pyclass.message(pyclass.seve.w, "LID", "Option /LOOP ignored with /FULL")
        # Get the frequency range of the current plot
        if image:
            (fmin,fmax) = pyclass.px_minmax("I")
        else:
            (fmin,fmax) = pyclass.px_minmax("F")
        # Do the job
        select_lines(fmin,fmax,species,Eu_max,Aij_min,image,threshold,angle,color)

    else:
        while True:
            # Prompt user to select the center signal frequency, image
            # frequency, channel or velocity (depending on the units of
            # the spectrum) with the mouse.

            pyclass.comm("greg\\draw relocate")

            if pyclass.gdict.cursor_code=='E':
                return

            # Get cursor X value, in current unit
            if units[0] == 'F'.encode():
                ival = frequency+float(use_curs[0])
            elif units[0] == 'I'.encode():
                ival = image_frequency+float(use_curs[0])
            else:
                ival = float(use_curs[0])

            # Convert to (absolute) Image or Frequency.
            # If the image option is set or if units are image, compute
            # the image frequency interval corresponding to the selected
            # frequency. In other cases, compute the signal frequency
            # interval.
            if image or units[0] == 'I'.encode():
                fval = pyclass.rx_val(ival,units[0],"I")
            else:
                fval = pyclass.rx_val(ival,units[0],"F")
            fmin = fval - abs(delta_freq)
            fmax = fval + abs(delta_freq)

            # Do the job
            select_lines(fmin,fmax,species,Eu_max,Aij_min,image,threshold,angle,color)

            # Loop?
            if not loop:
                return


if __name__ == "__main__":
    main()
