/*******************************************************************************
 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
 * Copyright (C) 2011 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
 *
 * This file is part of Jalview.
 *
 * Jalview is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License 
 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * Jalview is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty 
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
 * PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
package jalview.javascript;

import jalview.appletgui.AlignFrame;

/**
 * The following public methods may be called
 * externally, eg via javascript in an HTML page.
 * 
 * <br><em>TODO: introduce abstract interface for jalview.appletgui.AlignFrame</em><br>
 * 
 * Most function arguments are strings, which contain serialised versions of lists.
 * Lists of things are separated by a separator character - either the default or a user supplied one.
 * Ranges and positions on an alignment or sequence can be specified as a list, where an item containing a single number is a single position, and an item like 1-2 specifies columns 1 and 2 as a range.
 */

/**
 * @author jimp
 *
 */
public interface JalviewLiteJsApi
{

  /**
   * @return String list of selected sequence IDs, each terminated by the
   *         'boolean not' character (""+0x00AC) or (&#172;)
   */
  public abstract String getSelectedSequences();

  /**
   * @param sep
   *          separator string or null for default
   * @return String list of selected sequence IDs, each terminated by given
   *         separator string
   */
  public abstract String getSelectedSequences(String sep);

  /**
   * @param alf
   *          alignframe containing selection
   * @return String list of selected sequence IDs, each terminated by current
   *         default separator sequence
   * 
   */
  public abstract String getSelectedSequencesFrom(AlignFrame alf);

  /**
   * get list of selected sequence IDs separated by given separator
   * 
   * @param alf
   *          window containing selection
   * @param sep
   *          separator string to use - default is 'boolean not'
   * @return String list of selected sequence IDs, each terminated by the given
   *         separator
   */
  public abstract String getSelectedSequencesFrom(AlignFrame alf, String sep);

  /**
   * 
   * @param sequenceId
   *          id of sequence to highlight
   * @param position
   *          integer position [ tobe implemented or range ] on sequence
   * @param alignedPosition
   *          true/false/empty string - indicate if position is an alignment
   *          column or unaligned sequence position
   */
  public abstract void highlight(String sequenceId, String position,
          String alignedPosition);

  /**
   * 
   * @param sequenceId
   *          id of sequence to highlight
   * @param position
   *          integer position [ tobe implemented or range ] on sequence
   * @param alignedPosition
   *          false, blank or something else - indicate if position is an
   *          alignment column or unaligned sequence position
   */
  public abstract void highlightIn(AlignFrame alf, String sequenceId,
          String position, String alignedPosition);

  /**
   * select regions of the currrent alignment frame
   * 
   * @param sequenceIds
   *          String separated list of sequence ids or empty string
   * @param columns
   *          String separated list { column range or column, ..} or empty
   *          string
   */
  public abstract void select(String sequenceIds, String columns);

  /**
   * select regions of the currrent alignment frame
   * 
   * @param toselect
   *          String separated list { column range, seq1...seqn sequence ids }
   * @param sep
   *          separator between toselect fields
   */
  public abstract void select(String sequenceIds, String columns, String sep);

  /**
   * select regions of the given alignment frame
   * 
   * @param alf
   * @param toselect
   *          String separated list { column range, seq1...seqn sequence ids }
   * @param sep
   *          separator between toselect fields
   */
  public abstract void selectIn(AlignFrame alf, String sequenceIds,
          String columns);

  /**
   * select regions of the given alignment frame
   * 
   * @param alf
   * @param toselect
   *          String separated list { column range, seq1...seqn sequence ids }
   * @param sep
   *          separator between toselect fields
   */
  public abstract void selectIn(AlignFrame alf, String sequenceIds,
          String columns, String sep);

  /**
   * get sequences selected in current alignFrame and return their alignment in
   * format 'format' either with or without suffix
   * 
   * @param alf
   *          - where selection is
   * @param format
   *          - format of alignment file
   * @param suffix
   *          - "true" to append /start-end string to each sequence ID
   * @return selected sequences as flat file or empty string if there was no
   *         current selection
   */
  public abstract String getSelectedSequencesAsAlignment(String format,
          String suffix);

  /**
   * get sequences selected in alf and return their alignment in format 'format'
   * either with or without suffix
   * 
   * @param alf
   *          - where selection is
   * @param format
   *          - format of alignment file
   * @param suffix
   *          - "true" to append /start-end string to each sequence ID
   * @return selected sequences as flat file or empty string if there was no
   *         current selection
   */
  public abstract String getSelectedSequencesAsAlignmentFrom(
          AlignFrame alf, String format, String suffix);

  /**
   * get a separator separated list of sequence IDs reflecting the order of the current alignment 
   * @return
   */
  public abstract String getAlignmentOrder();
  /**
   * get a separator separated list of sequence IDs reflecting the order of the alignment in alf 
   *
   * @param alf
   * @return
   */
  public abstract String getAlignmentOrderFrom(AlignFrame alf);

  /**
   * get a sep separated list of sequence IDs reflecting the order of the alignment in alf 
   * 
   * @param alf
   * @param sep - separator to use
   * @return
   */
  public abstract String getAlignmentOrderFrom(AlignFrame alf, String sep);
  /**
   * re-order the current alignment using the given list of sequence IDs
   * @param order - sep separated list
   * @param undoName - string to use when referring to ordering action in undo buffer
   * @return 'true' if alignment was actually reordered. empty string if alignment did not contain sequences.
   */
  public abstract String orderBy(String order, String undoName);

  /**
   * re-order the current alignment using the given list of sequence IDs
   * separated by sep
   * 
   * @param order
   *          - sep separated list
   * @param undoName
   *          - string to use when referring to ordering action in undo buffer
   * @param sep
   * @return 'true' if alignment was actually reordered. empty string if alignment did not contain sequences.
   */
  public abstract String orderBy(String order, String undoName, String sep);

  /**
   * re-order the given alignment using the given list of sequence IDs
   * separated by sep
   * 
   * @param alf
   * @param order
   *          - sep separated list
   * @param undoName
   *          - string to use when referring to ordering action in undo buffer
   * @param sep
   * @return 'true' if alignment was actually reordered. empty string if alignment did not contain sequences.
   */
  public abstract String orderAlignmentBy(AlignFrame alf, String order,
          String undoName, String sep);

  /**
   * get alignment as format (format names FASTA, BLC, CLUSTAL, MSF, PILEUP, PFAM - see jalview.io.AppletFormatAdapter for full list)
   * @param format
   * @return
   */
  public abstract String getAlignment(String format);

  /**
   * get alignment displayed in alf as format
   * @param alf
   * @param format
   * @return
   */
  public abstract String getAlignmentFrom(AlignFrame alf, String format);

  /**
   * get alignment as format with jalview start-end sequence suffix appended
   * @param format
   * @param suffix
   * @return
   */
  public abstract String getAlignment(String format, String suffix);

  /**
   * get alignment displayed in alf as format 
   *  with or without the jalview start-end sequence suffix appended
   * @param alf
   * @param format
   * @param suffix
   * @return
   */
  public abstract String getAlignmentFrom(AlignFrame alf, String format,
          String suffix);

  /**
   * add the given features or annotation to the current alignment
   * @param annotation
   */
  public abstract void loadAnnotation(String annotation);

  /**
   * add the given features or annotation to the given alignment view
   * @param alf
   * @param annotation
   */
  public abstract void loadAnnotationFrom(AlignFrame alf, String annotation);

  /**
   * get the sequence features in the given format (Jalview or GFF)
   * @param format
   * @return
   */
  public abstract String getFeatures(String format);

  /**
   * get the sequence features in alf in the given format (Jalview or GFF)
   * @param alf
   * @param format
   * @return
   */
  public abstract String getFeaturesFrom(AlignFrame alf, String format);

  /**
   * get current alignment's annotation as an annotation file
   * @return
   */
  public abstract String getAnnotation();

  /**
   * get alignment view alf's annotation as an annotation file
   * @param alf
   * @return
   */
  public abstract String getAnnotationFrom(AlignFrame alf);

  /**
   * create a new view and return the alignFrame instance
   * @return
   */
  public abstract AlignFrame newView();

  /**
   * create a new view named name and return the alignFrame instance
   * @param name
   * @return
   */
  public abstract AlignFrame newView(String name);

  /**
   * create a new view on alf and return the alignFrame instance
   * @param alf
   * @return
   */
  public abstract AlignFrame newViewFrom(AlignFrame alf);

  /**
   * create a new view named name on alf
   * @param alf
   * @param name
   * @return
   */
  public abstract AlignFrame newViewFrom(AlignFrame alf, String name);

  /**
   * 
   * @param text
   *          alignment file as a string
   * @param title
   *          window title
   * @return null or new alignment frame
   */
  public abstract AlignFrame loadAlignment(String text, String title);

  /**
   * register a javascript function to handle any alignment mouseover events
   * @param listener name of javascript function  (called with arguments [jalview.appletgui.AlignFrame,String(sequence id),String(column in alignment), String(position in sequence)]
   */
  public abstract void setMouseoverListener(String listener);

  /**
   * register a javascript function to handle mouseover events
   * @param af (null or specific alignframe for which events are to be listened for)
   * @param listener name of javascript function 
   */
  public abstract void setMouseoverListener(AlignFrame af, String listener);

  /**
   * register a javascript function to handle any alignment selection events. Events are generated when the user completes a selection event, or when the user deselects all selected regions.
   * @param listener name of javascript function  (called with arguments [jalview.appletgui.AlignFrame, String(sequence set id), String(separator separated list of sequences which were selected), String(separator separated list of column ranges (i.e. single number or hyphenated range) that were selected)]
   */
  public abstract void setSelectionListener(String listener);

  public abstract void setSelectionListener(AlignFrame af, String listener);

  /**
   * register a javascript function to handle events normally routed to a Jmol structure viewer.
   * @param listener - javascript function (arguments are variable, see jalview.javascript.MouseOverStructureListener for full details)
   * @param modelSet - separator separated list of PDB file URIs that this viewer is handling. These files must be in the same order they appear in Jmol (e.g. first one is frame 1, second is frame 2, etc). 
     @see jalview.javascript.MouseOverStructureListener 
   */
  public abstract void setStructureListener(String listener, String modelSet);

  /**
   * remove any callback using the given listener function and associated with
   * the given alignFrame (or null for all callbacks)
   * 
   * @param af
   *          (may be null)
   * @param listener
   *          (may be null)
   */
  public abstract void removeJavascriptListener(AlignFrame af,
          String listener);

  /**
   * send a mouseover message to all the alignment windows associated with the
   * given residue in the pdbfile
   * 
   * @param pdbResNum
   * @param chain
   * @param pdbfile
   */
  public abstract void mouseOverStructure(String pdbResNum, String chain,
          String pdbfile);

  /**
   * bind a pdb file to a sequence in the given alignFrame.
   * 
   * @param alFrame
   *          - null or specific alignFrame. This specifies the dataset that
   *          will be searched for a seuqence called sequenceId
   * @param sequenceId
   *          - sequenceId within the dataset.
   * @param pdbEntryString
   *          - the short name for the PDB file
   * @param pdbFile
   *          - pdb file - either a URL or a valid PDB file.
   * @return true if binding was as success TODO: consider making an exception
   *         structure for indicating when PDB parsing or sequenceId location
   *         fails.
   */
  public abstract boolean addPdbFile(AlignFrame alFrame, String sequenceId,
          String pdbEntryString, String pdbFile);

  /**
   * adjust horizontal/vertical scroll to make the given location the top left hand corner for the given view
   * 
   * @param alf
   * @param topRow
   * @param leftHandColumn
   */
  public abstract void scrollViewToIn(AlignFrame alf, String topRow,
          String leftHandColumn);
  /**
   * adjust vertical scroll to make the given row the top one for given view
   * 
   * @param alf
   * @param topRow
   */
  public abstract void scrollViewToRowIn(AlignFrame alf, String topRow);
  /**
   * adjust horizontal scroll to make the given column the left one in the given view
   * 
   * @param alf
   * @param leftHandColumn
   */
  public abstract void scrollViewToColumnIn(AlignFrame alf, String leftHandColumn);

  /**
   * 
   * @return
   * @see jalview.appletgui.AlignFrame#getFeatureGroups()
   */
  public abstract String getFeatureGroups();

  /**
   * @param alf
   *          alignframe to get feature groups on
   * @return
   * @see jalview.appletgui.AlignFrame#getFeatureGroups()
   */
  public abstract String getFeatureGroupsOn(AlignFrame alf);

  /**
   * @param visible
   * @return
   * @see jalview.appletgui.AlignFrame#getFeatureGroupsOfState(boolean)
   */
  public abstract String getFeatureGroupsOfState(boolean visible);

  /**
   * @param alf
   *          align frame to get groups of state visible
   * @param visible
   * @return
   * @see jalview.appletgui.AlignFrame#getFeatureGroupsOfState(boolean)
   */
  public abstract String getFeatureGroupsOfStateOn(AlignFrame alf,
          boolean visible);

  /**
   * @param groups
   *          tab separated list of group names
   * @param state
   *          true or false
   * @see jalview.appletgui.AlignFrame#setFeatureGroupState(java.lang.String[],
   *      boolean)
   */
  public abstract void setFeatureGroupStateOn(AlignFrame alf,
          String groups, boolean state);

  public abstract void setFeatureGroupState(String groups, boolean state);

  /**
   * List separator string
   * 
   * @return the separator
   */
  public abstract String getSeparator();

  /**
   * List separator string
   * 
   * @param separator
   *          the separator to set. empty string will reset separator to default
   */
  public abstract void setSeparator(String separator);

  /**
   * Retrieve fragments of a large packet of data made available by JalviewLite.
   * @param messageclass
   * @param viewId
   * @return next chunk of message
   */
  public abstract String getJsMessage(String messageclass, String viewId);

}