package apollo.gui;

import java.awt.Color;
import java.awt.Font;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.StreamTokenizer;
import java.util.*;
import javax.swing.JOptionPane;
import org.bdgp.io.DataAdapterException;
import org.bdgp.io.DataAdapterRegistry;
import apollo.dataadapter.organism.*;
import apollo.gui.schemes.FeatureProperty;
import apollo.gui.schemes.PropertyScheme;

/** A Style is basically config options for a particular data adapter */

public class Style {

  private static PropertyScheme    properties;
  private String tiersFile;
  private String blixemLocation=null;
  private boolean showAnnotations=false;
  private float   percentSpaceForAnnotations=50;
  //  private boolean doHorribleVerticalLayoutHack=false;
  private boolean showResults=true;
  private boolean editingEnabled=false;
  private boolean navigationManagerEnabled=false;
  private Vector chromosomes;
    // Should we set some default types if none are listed in Style file?
  private Vector annotationTypeList;  // Annotation types (gene, tRNA, etc.)
  private Vector cannedComments; // comment strings
  private Hashtable userToColor; // = new Hashtable();
  private Hashtable userToProject; // = new Hashtable();
  private Hashtable userToFullName;
  private Hashtable peptideStates = new Hashtable();
  private boolean verticallyMovePopups = true;
  private boolean doHaveSequenceHack = false;
  /** URL string that takes a gene name and spits back the region with that gene*/
  private String geneUrl;
  private String scaffoldUrl;
  /** Url string: band -> data for band */
  private String bandUrl;
  private String seqUrl;
  private String rangeUrl;
  private OrganismAdapterI organism 
    = new apollo.dataadapter.organism.OrganismAdapter();
  private String styleFileString;

  private Color             coordBackground = Color.white;
  private Color             coordForeground = Color.black;
  private Color             coordRevcompColor = Color.red;
  private Color             featureBackground = Color.black;
  private Color             annotationBackground = Color.cyan;
  private Color             edgematchColor = Color.black;
  private Color             highlightColor = Color.green;
  private Color             selectionColor = Color.red;
  private Color             seqGapColor = Color.yellow;
  private Color             featureLabelColor = Color.white;
  private Color             annotationLabelColor = Color.black;
  private Color             edeBackgroundColor1 = Color.gray;
  private Color             edeBackgroundColor2 = Color.black;
  private Color             edeFeatureColor1 = Color.blue;
  private Color             edeFeatureColor2 = new Color(0,0,180);
  private boolean           dashSets = false;
  private int               edgematchWidth = 2;
  private Color             sequenceColor = coordForeground;
  private boolean           noStripes = true;
  private boolean           draw3D = false;
  private boolean           drawOutline = false;
  private boolean           userTranscriptColouring = false;
  private boolean           fastClipGraphics = true;
  // Used for deciding whether to show internal-only comments.
  // this is used in preference to the external ref URL
  private String projectRefUrl = null;
  /** Should probably be a vector of external refs with dbname:url format? */
  private String externalRefUrl;
  private java.util.List syntenySpeciesOrder = new java.util.ArrayList();
  private java.util.List syntenyAdapterOrder = new java.util.ArrayList();
  private HashMap syntenySpeciesNames = new HashMap();
  private HashMap syntenySpeciesProperties = new HashMap();
  private Font defaultFont = new Font("Dialog",0,9); // Arial 9 no good on red hat
  private Font defaultFeatureLabelFont = new Font("Dialog",0,9);
  private Font exonDetailEditorSequenceFont = new Font("Courier", Font.BOLD, 12);
  private String defaultNameAdapter = "apollo.dataadapter.organism.DefaultNameAdapter";
  private Color defaultUserColor = Color.orange;
  private int featureLoadSize = 1000000;

  private String errors = "";
  private int lineNum = 0;
  
  private boolean naiveCrossSpeciesDataLoading = false;
  private boolean useOpaqueLinks = true;

  public Style(String styleFileString) {
    File styleFile = new File(styleFileString);
    this.styleFileString = styleFileString;
    readStyle(styleFile);
  }

  // Saves error messages for later checking
  private void readStyle(File styleFile) {
//      System.out.println("Reading style "+styleFile);  // DEL
    try {
      StreamTokenizer tokenizer =
        new StreamTokenizer(new BufferedReader(new FileReader(styleFile)));
      tokenizer.eolIsSignificant(true);
      tokenizer.slashStarComments(true);
      boolean endOfFile     =  false;
      int     tokType =  0;
      ArrayList  lineWords   =  new ArrayList();

      while (!endOfFile) {
        tokType =  tokenizer.nextToken(); // token iteration
        if (tokType == StreamTokenizer.TT_EOF) {
          endOfFile = true; // end of file - break loop
        }
        else if (tokType != StreamTokenizer.TT_EOL) {
          if (tokenizer.sval != null) { // grab words til end of line
            lineWords.add(tokenizer.sval);
          }
	  ++lineNum;
        } 	// hit end of line - do something with parsed words only if 2 of them
        else if (lineWords.size() == 2) {
          String key   = (String)lineWords.get(0);
          String value = (String)lineWords.get(1);
          if (key.equals("Types")) {
            tiersFile = new String(value);
            tiersFile = Config.findFile(tiersFile);
	    if (tiersFile == null) {
		complain("Types file " + value + " not found");
		return;  // Give up now?
	    }
          } else if (key.equals("BlixemLocation")) {
            blixemLocation = new String(value);
          
          } else if (key.equalsIgnoreCase("ShowAnnotations")) {
	    if (checkBoolean(value, "ShowAnnotations"))
	      showAnnotations = (new Boolean(value)).booleanValue();
//           } else if (key.equalsIgnoreCase("PercentSpaceForAnnotations")) {
//             try {
//               percentSpaceForAnnotations = Float.valueOf(value).floatValue();
//               doHorribleVerticalLayoutHack = true;
//             } catch (NumberFormatException e) {
//               System.err.println("Can't parse number for percentSpaceForAnnotations: "+value);
//             }
          } else if (key.equalsIgnoreCase("ShowResults")) {
	    if (checkBoolean(value, "ShowResults"))
	      showResults = (new Boolean(value)).booleanValue();
          } else if (key.equalsIgnoreCase("EnableEditing")) {
	    if (checkBoolean(value, "EnableEditing"))
	      editingEnabled = (new Boolean(value)).booleanValue();
          } else if (key.equalsIgnoreCase("EnableNavigationManager")) {
	    if (checkBoolean(value, "EnableNavigationManager"))
	      navigationManagerEnabled = (new Boolean(value)).booleanValue();
          } else if (key.equalsIgnoreCase("Chromosomes")) {
            chromosomes = parseStringIntoVector(value);
          } else if (key.equalsIgnoreCase("AnnotationTypes")) {
            annotationTypeList = parseStringIntoVector(value);
          } else if (key.equalsIgnoreCase("CommentOption")) {
            addCannedComment(value);
          } else if (key.equalsIgnoreCase("UserInfo")) {
            addUserInfo(value);
          } else if (key.equalsIgnoreCase("PeptideStatus")) {
            addPeptideStatus(value);
          } else if (key.equalsIgnoreCase("FeatureLoadSize")) {
            addFeatureLoadSize(Integer.valueOf(value).intValue());
          } else if (key.equalsIgnoreCase("GeneURL")) {
            geneUrl = value;
          } else if (key.equalsIgnoreCase("BandURL")) {
            bandUrl = value;
          } else if (key.equalsIgnoreCase("ScaffoldURL")) {
            scaffoldUrl = value;
          } else if (key.equalsIgnoreCase("SequenceURL")) {
            seqUrl = value;
          } else if (key.equalsIgnoreCase("RangeURL")) {
            rangeUrl = value;
          } else if (key.equalsIgnoreCase("ExternalRefURL")) {
            externalRefUrl = value;
          } else if (key.equalsIgnoreCase("ProjectRefURL")) {
	      projectRefUrl = value;
	      System.out.println("Running in internal mode\n");
          } else if (key.equalsIgnoreCase("NameAdapterInstall")) {
            installNameAdapter(value);
          } else if (key.equalsIgnoreCase("OverlapDefinition")) {
            setOverlapper(value);
	  } else if (key.equalsIgnoreCase("GeneDefinition")) {
	    setGeneDefinition(value);
	  } else if (key.equalsIgnoreCase("HaveSequenceHack")) {
	    if (checkBoolean(value, "HaveSequenceHack"))
	      doHaveSequenceHack = (new Boolean(value)).booleanValue();
          } else if (key.equalsIgnoreCase("DashSets")) {
	    if (checkBoolean(value, "DashSets"))
	      dashSets = (new Boolean(value)).booleanValue();
          } else if (key.equalsIgnoreCase("FeatureBackgroundColor")) {
	    if (checkValidColor(value, "FeatureBackgroundColor"))
	      setFeatureBackground(FeatureProperty.toColour(value,
							    featureBackground));
          } else if (key.equalsIgnoreCase("AnnotationBackgroundColor")) {
	    if (checkValidColor(value, "AnnotationBackgroundColor"))
	      setAnnotationBackground(FeatureProperty.toColour(value,
							       annotationBackground));
          } else if (key.equalsIgnoreCase("EdgematchWidth")) {
            try {
              edgematchWidth = (Integer.valueOf(value).intValue());
            } catch (NumberFormatException e) {
              complain("Can't parse number for EdgematchWidth: "+value);
            }
          } else if (key.equalsIgnoreCase("EdgematchColor")) {
	    if (checkValidColor(value, "EdgematchColor"))
	      edgematchColor = FeatureProperty.toColour(value,
							edgematchColor);
          } else if (key.equalsIgnoreCase("AnnotationLabelColor")) {
	    if (checkValidColor(value, "AnnotationLabelColor"))
	      setAnnotationLabelColor(FeatureProperty.toColour(value,
							       annotationLabelColor));
          } else if (key.equalsIgnoreCase("LabelColor") || key.equalsIgnoreCase("featureLabelColor")) {
	    if (checkValidColor(value, "FeatureLabelColor"))
		setFeatureLabelColor(FeatureProperty.toColour(value,
							      featureLabelColor));
            } else if (key.equalsIgnoreCase("DefaultAnnotationColor")) {
	      if (checkValidColor(value, "DefaultAnnotationColor"))
		// Is this a good idea?
		Config.defaultAnnotationColor = FeatureProperty.toColour(value,
									 Config.defaultAnnotationColor);
            } else if (key.equalsIgnoreCase("HighlightColor")) {
	      if (checkValidColor(value, "HighlightColor"))
		highlightColor = FeatureProperty.toColour(value,
							  highlightColor);
            } else if (key.equalsIgnoreCase("SelectionColor")) {
	      if (checkValidColor(value, "SelectionColor"))
		selectionColor = FeatureProperty.toColour(value,
							  selectionColor);
            } else if (key.equalsIgnoreCase("CoordBackgroundColor")) {
	      if (checkValidColor(value, "CoordBackgroundColor"))
		coordBackground = FeatureProperty.toColour(value,
							   coordBackground);
            } else if (key.equalsIgnoreCase("SequenceColor")) {
	      if (checkValidColor(value, "SequenceColor"))
		sequenceColor = FeatureProperty.toColour(value,
							 sequenceColor);
            } else if (key.equalsIgnoreCase("ExonDetailEditorBackgroundColor1")) {
	      if (checkValidColor(value, "ExonDetailEditorBackgroundColor1"))
		edeBackgroundColor1 = FeatureProperty.toColour(value,edeBackgroundColor1);
            } else if (key.equalsIgnoreCase("ExonDetailEditorBackgroundColor2")) {
	      if (checkValidColor(value, "ExonDetailEditorBackgroundColor2"))
		edeBackgroundColor2 = FeatureProperty.toColour(value,edeBackgroundColor2);
            } else if (key.equalsIgnoreCase("ExonDetailEditorFeatureColor1")) {
	      if (checkValidColor(value, "ExonDetailEditorFeatureColor1"))
		edeFeatureColor1 = FeatureProperty.toColour(value,edeFeatureColor1);
            } else if (key.equalsIgnoreCase("ExonDetailEditorFeatureColor2")) {
	      if (checkValidColor(value, "ExonDetailEditorFeatureColor2"))
		edeFeatureColor2 = FeatureProperty.toColour(value,edeFeatureColor2);
            } else if (key.equalsIgnoreCase("DashSets")) {
	      if (checkBoolean(value, "DashSets"))
		dashSets = (new Boolean(value)).booleanValue();
            } else if (key.equalsIgnoreCase("FastClipGraphics")) {
	      if (checkBoolean(value, "FastClipGraphics"))
		fastClipGraphics = (new Boolean(value)).booleanValue();
            } else if (key.equalsIgnoreCase("UserTranscriptColouring") ||
		       key.equalsIgnoreCase("UserTranscriptColoring")) {
	      if (checkBoolean(value, "UserTranscriptColoring"))
		userTranscriptColouring = (new Boolean(value)).booleanValue();
            } else if (key.equalsIgnoreCase("Draw3D")) {
	      if (checkBoolean(value, "Draw3D"))
		draw3D = (new Boolean(value)).booleanValue();
            } else if (key.equalsIgnoreCase("DrawOutline")) {
	      if (checkBoolean(value, "drawOutline"))
		drawOutline = (new Boolean(value)).booleanValue();
            } else if (key.equalsIgnoreCase("NoStripes")) {
	      if (checkBoolean(value, "NoStripes"))
		noStripes = (new Boolean(value)).booleanValue();
            } else if (key.equalsIgnoreCase("CoordForegroundColor")) {
	      if (checkValidColor(value, "CoordForegroundColor"))
		coordForeground = FeatureProperty.toColour(value,
							   coordForeground);
            } else if (key.equalsIgnoreCase("SequenceGapColor")) {
	      if (checkValidColor(value, "SequenceGapColor"))
		seqGapColor = FeatureProperty.toColour(value,
						       seqGapColor);

          } else if (key.equalsIgnoreCase("VerticallyMovePopups")) {
	    if (checkBoolean(value, "VerticallyMovePopups"))
	      verticallyMovePopups = (new Boolean(value)).booleanValue();
          } else if (key.startsWith("Name")) {
            //Synteny species logical-and-species-names.
            getSyntenySpeciesNames().put(key, value);
            getSyntenyAdapterOrder().add(key);
            if(!value.equals("Compara")){
              getSyntenySpeciesOrder().add(key);
            }
          } else if (key.startsWith("Species")) {
            //Synteny species property.
            getSyntenySpeciesProperties().put(key, value);
	  } else if (key.equalsIgnoreCase("NaiveCrossSpeciesDataLoading")) {
	    naiveCrossSpeciesDataLoading = Boolean.valueOf(value).booleanValue();
	  } else if (key.equalsIgnoreCase("useOpaqueLinks")) {
	    useOpaqueLinks = Boolean.valueOf(value).booleanValue();
	  } else if (key.equalsIgnoreCase("DefaultFont")) {
	    defaultFont = parseFont(value);
	  } else if (key.equalsIgnoreCase("DefaultFeatureLabelFont")) {
	    defaultFeatureLabelFont = parseFont(value);
	  } else if (key.equalsIgnoreCase("ExonDetailEditorSequenceFont")) {
	    exonDetailEditorSequenceFont = parseFont(value);
          } else {
	    complain("Unknown style key " + key);
          }
	  lineWords.clear(); // empty for next line
        }
        else if (lineWords.size() != 0) {
          String error = "Line has too many words: " + lineWords.get(0) + " " + lineWords.get(1) + " " + lineWords.get(2) + " (etc.)";
          complain(error);
	  lineWords.clear(); // empty for next line
        }
      }

    } catch (FileNotFoundException e) {
      JOptionPane.showMessageDialog(null,"Style file "+styleFile+" not found");
    }
    catch (IOException e) {
      String error = "Error parsing style file "+styleFile+": " + e;
      complain(error);
      JOptionPane.showMessageDialog(null,error);
    }
    catch (Exception e) {
      String error = "Error parsing style file "+styleFile+": " + e;
      complain(error);
    }
  }

  public void complain(String message) {
    System.err.println("Error on line " + lineNum + " of " + styleFileString + ":\n  " + message);
    errors = errors + "\n" + "Error on line " + lineNum + " of " + styleFileString + ":\n   " + message;
  }

  public String getErrors() {
    return errors;
  }

  public boolean checkValidColor(String colorStr, String variableName) {
    Color color;
    try {
      color = FeatureProperty.parseColour(colorStr);
    } catch (NumberFormatException e) {
      complain("Bad color " + colorStr + " for " + variableName);
      return false;
    }
    return true;
  }

  public String getBlixemLocation() {
    if (blixemLocation == null)
      return null;

    // FOR NOW just decide whether to use the linux or solaris version
    String osname = System.getProperty("os.name");
    // Are there other Linux osnames not caught by this pattern?
    if (osname.startsWith("Linux") || osname.startsWith("linux"))
      blixemLocation = "bin/blixem.LINUX";
    else if (osname.startsWith("Solaris") ||
             osname.startsWith("Sun"))
      blixemLocation = "bin/blixem.SOLARIS";

    String absolute_path = Config.findFile(blixemLocation);
    return absolute_path;
  }


  public boolean checkBoolean(String value, String variableName) {
    if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false"))
      return true;
    else {
      complain("Value " + value + " for " + variableName + " is not boolean (should be true or false)");
      return false;
    }
  }

  String getTiersFile() {
    return tiersFile;
  }

  public boolean getShowAnnotations() {
    return showAnnotations;
  }

  public boolean getShowResults() {
    return showResults;
  }
  public int getEdgematchWidth() {
    return edgematchWidth;
  }

  public boolean doUserTranscriptColouring() {
    return userTranscriptColouring;
  }
  public boolean getDraw3D() {
    return draw3D;
  }
  public void setDraw3D(boolean state) {
    draw3D = state;
  }
  public boolean getNoStripes() {
    return noStripes;
  }

  boolean verticallyMovePopups() {
    return verticallyMovePopups;
  }

  boolean isEditingEnabled() {
    return editingEnabled;
  }

  boolean doHaveSequenceHack() {
    return doHaveSequenceHack;
  }

  boolean isNavigationManagerEnabled() {
    return navigationManagerEnabled;
  }

  boolean hasChromosomes() {
    return chromosomes!=null;
  }
  /** Returns a vector of chromosome names as strings, null if none given */
  public Vector getChromosomes() {
    return chromosomes;
  }

  public boolean getDrawOutline() {
    return drawOutline;
  }

  public void setDrawOutline(boolean state) {
    drawOutline = state;
  }

  public Vector getAnnotationTypeList() {
      if (annotationTypeList == null) {
	  annotationTypeList = new Vector();
	  annotationTypeList.add("gene");
	  annotationTypeList.add("other");
      }
      return annotationTypeList;
  }

  /** parses string (e.g. "2L,2R,3L,3R,4,X") into vector */
  private Vector parseStringIntoVector(String string) {
    Vector v = new Vector();
    StringTokenizer tokenizer = new StringTokenizer(string,",");
    while (tokenizer.hasMoreTokens())
      v.addElement(tokenizer.nextToken().trim());
    return v;
  }

  Vector getCannedComments() {
    return cannedComments;
  }

  private void addCannedComment(String comment) {
    if (cannedComments==null) {
      cannedComments = new Vector();
      cannedComments.addElement("Select comment or enter your own");
    }
    cannedComments.addElement(comment);
  }

  // Used for deciding whether to show internal-only comments.
  public boolean internalMode() {
    return (projectRefUrl != null);
  }

  public String getProjectName (String username) {
    String projectname = null;
    if (userToProject != null && !internalMode() && username != null)
      projectname = (String) userToProject.get(username);
    return (projectname == null ? username : projectname);
  }
	    
  /** Retrieve color for user name; if no color use defaultAnnotationColor
   *  Note that this is called only if doUserTranscriptColouring is true. */
  //  Color getAnnotationColor(String username, FeatureProperty fp) {
  public Color getAnnotationColor(String username) {
    Color color = null;
    if (username == null || username.trim().length() <=0 ||
        username.equalsIgnoreCase("auto") || userToColor == null) {
      color = Config.defaultAnnotationColor;
    } else {
      color = (Color) userToColor.get(username);
      if (color == null)
        // color = fp.getColour();
	color = Config.defaultAnnotationColor;
    }
    return color;
  }

  private void addUserInfo(String userinfo) {
    StringTokenizer tokens = new StringTokenizer (userinfo, ":");
    String user = null;
    String project = null;
    Color color = null;
    String full_name = null;
    while (tokens.hasMoreTokens()) {
      String tagval = tokens.nextToken();
      int breakIndex = tagval.indexOf("=");
      if (breakIndex > 0) {
	String tag = tagval.substring(0, breakIndex);
	String val = tagval.substring(breakIndex+1);
	if (tag.equals("user"))
	  user = val;
	else if (tag.equals ("project"))
	  project = val;
	else if (tag.equals ("color"))
	  color = FeatureProperty.toColour(val,defaultUserColor);
	else if (tag.equals("full-name"))
	  full_name = val;
      }
    }
    if (user != null) {
      if (project != null) {
	if (userToProject==null)
	  userToProject = new Hashtable();
	userToProject.put(user, project);
      }
      if (color != null) {
	if (userToColor==null)
	  userToColor = new Hashtable();
	userToColor.put(user, color);
      }
      if (full_name != null) {
	if (userToFullName==null) userToFullName = new Hashtable();
	userToFullName.put(user,full_name);
      }
    }
    if (user == null || color == null)
      complain("Bad user info string: " + userinfo);
  }

  Hashtable getPeptideStates () {
    return peptideStates;
  }

  PeptideStatus getPeptideStatus(String pep_status) {
    if (pep_status == null || pep_status.equals (""))
      // this is certain to be found
      pep_status = "not analyzed";
    else
      pep_status = pep_status.toLowerCase();
    PeptideStatus status = (PeptideStatus) peptideStates.get (pep_status);
    if (status == null) {
      status = new PeptideStatus();
      peptideStates.put (pep_status, status);
      System.out.println ("Had to create a default for peptide status " +
                          pep_status);
    }
    return status;
  }

  private void addFeatureLoadSize(int size) {
    this.featureLoadSize = size;
  }
  public int getFeatureLoadSize() {
    return featureLoadSize;
  }
  private void addPeptideStatus(String peptideString) {
    PeptideStatus status = new PeptideStatus ();
    String peptide_key = status.initStatus (peptideString);
    if (peptideStates==null)
      peptideStates = new Hashtable();
    peptideStates.put(peptide_key.toLowerCase(), status);
  }

  public String getGeneUrl() {
    return geneUrl;
  }

  public String getBandUrl() {
    return bandUrl;
  }

  public String getScaffoldUrl() {
    return scaffoldUrl;
  }

  public String getSeqUrl() {
    return seqUrl;
  }

  public String getRangeUrl() {
    return rangeUrl;
  }

  String getExternalRefUrl() {
    // If we're internal to the project, get web internal report pages 
      // instead of integrated gene reports.
      return (projectRefUrl != null ? projectRefUrl : externalRefUrl);
  }

  public boolean getDashSets() {
    return dashSets;
  }

  public Color getAnnotationBackground() {
    return annotationBackground;
  }

  public void setAnnotationBackground(Color color) {
    annotationBackground = color;
  }

  public Color getFeatureBackground() {
    return featureBackground;
  }
  public void setFeatureBackground(Color col) {
    featureBackground = col;
  }

  public Color getEdgematchColor() {
    return edgematchColor;
  }
  public void setEdgematchColor(Color col) {
    edgematchColor = col;
  }

  public Color getFeatureLabelColor() {
    return featureLabelColor;
  }

  public void setFeatureLabelColor(Color col) {
    featureLabelColor = col;
  }

  public Color getAnnotationLabelColor() {
    return annotationLabelColor;
  }

  public void setAnnotationLabelColor(Color col) {
    annotationLabelColor = col;
  }

  public Color getCoordBackground() {
    return coordBackground;
  }
  public void setCoordBackground(Color col) {
    coordBackground = col;
  }

  public Color getCoordForeground() {
    return coordForeground;
  }
  public void setCoordForeground(Color col) {
    coordForeground = col;
  }

  public Color getCoordRevcompColor() {
    return coordRevcompColor;
  }
  public void setCoordRevcompColor(Color col) {
    coordRevcompColor = col;
  }

  public Color getSequenceColor() {
    return sequenceColor;
  }
  public void setSequenceColor(Color col) {
    sequenceColor = col;
  }

  public Color getHighlightColor() {
    return highlightColor;
  }

  public Color getSelectionColor() {
    return selectionColor;
  }

  public Color getSeqGapColor() {
    return seqGapColor;
  }
  
  Color getExonDetailEditorBackgroundColor1() {
    return edeBackgroundColor1;
  }
  Color getExonDetailEditorBackgroundColor2() {
    return edeBackgroundColor2;
  }
  Color getExonDetailEditorFeatureColor1() {
    return edeFeatureColor1;
  }
  Color getExonDetailEditorFeatureColor2() {
    return edeFeatureColor2;
  }

  private void installNameAdapter(String nameString) {
    try {
      Class namerClass = Class.forName(nameString);
      ApolloNameAdapterI nameAdapter
	= (ApolloNameAdapterI) namerClass.newInstance();
      organism.setNameAdapter (nameAdapter);
    } catch (Exception e) {
      System.out.println ("Could not find " + nameString + 
			  " err " + e.getMessage());
    }
  }

  public ApolloNameAdapterI getNameAdapter() {
    if (organism.getNameAdapter() == null)
      installNameAdapter(defaultNameAdapter);

    return organism.getNameAdapter();
  }

  private void setOverlapper (String classString) {
    try {
      Class overlapClass = Class.forName(classString);
      OverlapI overlapper = (OverlapI) overlapClass.newInstance();
      organism.setOverlapper (overlapper);
    } catch (Exception e) {
      System.out.println ("Could not find " + classString + 
			  " err " + e.getMessage());
    }
  }

  public OverlapI getOverlapper() {
    return organism.getOverlapper();
  }

  private void setGeneDefinition (String orgString) {
    organism.setGeneDefinition (orgString);
  }

  public int getGeneDefinition() {
    return organism.getGeneDefinition();
  }

  public HashMap getSyntenySpeciesNames(){
    return syntenySpeciesNames;
  }//end getSyntenySpeciesNames

  public HashMap getSyntenySpeciesProperties(){
    return syntenySpeciesProperties;
  }//end getSyntenySpeciesProperties

  public List getSyntenySpeciesOrder(){
    return syntenySpeciesOrder;
  }//end getSyntenySpeciesNames
  
  public List getSyntenyAdapterOrder(){
    return syntenyAdapterOrder;
  }//end getSyntenyAdapterOrder
  
  public String getFileName() {
    return styleFileString;
  }

  /** Default font for all of apollo in theory, used for axis labels */
  Font getDefaultFont() { 
    return defaultFont; 
  }

  /** Default font for gene label if it does not have a peptide status(which has a font) 
      gene label appears as label to feature and in gene menu list */
  Font getDefaultFeatureLabelFont() {
    return defaultFeatureLabelFont;
  }

  /** Font for amino and dna sequence in EDE */
  public Font getExonDetailEditorSequenceFont() {
    return exonDetailEditorSequenceFont;
  }
  
  /**
   * This indicates whether a composite adapter UI is to load cross-species data
   * simply - that is, just read the adapters for each species & the compara sets 
   * in turn, and not propagate information from one read to the other.
  **/
  public boolean getNaiveCrossSpeciesDataLoading(){
    return naiveCrossSpeciesDataLoading;
  }
 
  /**
   * If the links between individual species' features are drawn opaquely
   * then rendering of the panels as a whole will be faster.
  **/
  public boolean useOpaqueLinks(){
    return useOpaqueLinks;
  }
 
  /** font_str is composed of 3 comma delimited fields:
      fontname,fontstyle,fontsize (9 is the default)
              fontstyle can be 0,1,2,3 (plain, bold, italic, bolditalic)  
  */
  static Font parseFont (String font_str) {
    StringTokenizer tokenizer = new StringTokenizer(font_str, ",");
    // this is the default font
    String font_name = "Dialog"; // "Arial";
    int font_style = Font.PLAIN;
    int font_size = 9;
    Font font = null;

    try {
      if (tokenizer.hasMoreTokens()) {
        font_name = tokenizer.nextToken();
      }
      if (tokenizer.hasMoreTokens()) {
        font_style = Integer.parseInt(tokenizer.nextToken());
      }
      if (tokenizer.hasMoreTokens()) {
        font_size = Integer.parseInt(tokenizer.nextToken());
      }
      font = new Font(font_name, font_style, font_size);
    } catch (Exception e) {
      System.out.println ("Failed to parse Font from " + font_str);
    }
    return font;
  }

  public String toString() {
    return(getFileName());
  }

  /** Returns full name of user - if dont have full name just returns user */
  String getFullNameForUser(String user) {
    if (user == null) return null;
    if (userToFullName == null) return user;
    String fullName = (String)userToFullName.get(user);
    if (fullName == null) return user;
    return fullName;
  }    

    public PropertyScheme getPropertyScheme() {
	if (properties == null) {
	    try {
		properties = new PropertyScheme();
	    }
	    catch (Exception e) {
		String msg = ("Failed to parse tiers file " + tiersFile);
		JOptionPane.showMessageDialog(null,msg,"Warning",
					      JOptionPane.WARNING_MESSAGE);
	    }
	}
	return properties;
    }


}
