/* BEGIN_HEADER                                              Java TreeView
 *
 * $Author: alokito $
 * $RCSfile: TextView.java,v $
 * $Revision: 1.4 $
 * $Date: 2010-05-02 13:39:00 $
 * $Name:  $
 *
 * This file is part of Java TreeView
 * Copyright (C) 2001-2014 Alok Saldanha, All Rights Reserved. Modifications Copyright (C) Lawrence Berkeley Lab.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * END_HEADER 
 */
package edu.stanford.genetics.treeview.plugin.dendroview;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Observable;

import javax.swing.JScrollPane;

import edu.stanford.genetics.treeview.*;

public class TextView extends ModelView implements FontSelectable,
		KeyListener, AdjustmentListener,
		MouseListener, MouseMotionListener {

	public String[]  getHints() {
		String [] hints = {
				"Click and drag to scroll",
		};
		return hints;
	}

	/**
	 * should really take a HeaderSummary instead of HeaderInfo, since the mapping should be managed by
	 * Dendroview so that the SummaryView can use the same HeaderSummary.
	 */
	public TextView(HeaderInfo hI, UrlExtractor uExtractor) {
		super();
		urlExtractor = uExtractor;
		headerInfo = hI;
		col = -1;

		//  could set up headerSummary...
		int GIDIndex = headerInfo.getIndex("GID");
		if (GIDIndex == -1) {
			headerSummary.setIncluded(new int [] {1});
		} else {
			headerSummary.setIncluded(new int [] {2});
		}

		//		int yorfIndex = headerInfo.getIndex("YORF");
		//	int nameIndex = headerInfo.getIndex("NAME");

		addMouseListener(this);
		addMouseMotionListener(this);
		addKeyListener(this);

		scrollPane = new JScrollPane(this);
		scrollPane.setBorder(null);
		panel = scrollPane;
	}


	public TextView(HeaderInfo hI, UrlExtractor uExtractor, int col) {
		super();
		urlExtractor = uExtractor;
		headerInfo = hI;
		this.col = col;

		//  could set up headerSummary...
		int GIDIndex = headerInfo.getIndex("GID");
		if (GIDIndex == -1) {
			headerSummary.setIncluded(new int [] {1});
		} else {
			headerSummary.setIncluded(new int [] {2});
		}

		//		int yorfIndex = headerInfo.getIndex("YORF");
		//	int nameIndex = headerInfo.getIndex("NAME");

		addMouseListener(this);
		addMouseMotionListener(this);
		addKeyListener(this);

		scrollPane = new JScrollPane(this);
		scrollPane.setBorder(null);
		panel = scrollPane;
	}

	public String viewName() { return "TextView";}

	// I bet this isn't used anymore.
	public MenuItem getFontMenuItem() {

		MenuItem itema = new MenuItem("Gene Font...");
		itema.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent actionEvent)
			{
				FontSelector fontSelector = new FontSelector
						(TextView.this, "Select Fonts for Gene Info");
				fontSelector.showDialog(viewFrame);
			}
		});

		return itema;
	}

	// Canvas methods

	public void updateBuffer(Graphics g) {
		updateBuffer(g, offscreenSize);
	}
	public void updateBuffer(Image buf) {
		Dimension offscreenSize = new Dimension(buf.getWidth(null), buf.getHeight(null));
		updateBuffer(buf.getGraphics(), offscreenSize);
	}


	public void updateBuffer(Graphics g, Dimension offscreenSize) {
		// clear the pallette...
		g.setColor(Color.white);
		g.fillRect(0,0, offscreenSize.width, offscreenSize.height);
		g.setColor(Color.black);

		if ((map.getMinIndex() >= 0) &&
				(offscreenSize.height > 0)) {

			int start = map.getIndex(0);
			int end =   map.getIndex(map.getUsedPixels());
			g.setFont(new Font(face, style, size));
			FontMetrics metrics = getFontMetrics(g.getFont());
			int ascent = metrics.getAscent();

			// draw backgrounds first...
			int bgColorIndex = headerInfo.getIndex("BGCOLOR");
			if (bgColorIndex > 0) {
				Color back = g.getColor();
				for (int j = start; j < end;j++) {
					if ((geneSelection == null) || geneSelection.isIndexSelected(j)) {
						String [] strings = headerInfo.getHeader(j);
						try {
							g.setColor(TreeColorer.getColor(strings[bgColorIndex]));
						} catch (Exception e) {
							// ignore
						}
						g.fillRect(0, map.getMiddlePixel(j) - ascent / 2, offscreenSize.width, ascent);
					}
				}
				g.setColor(back);
			}

			// now, foreground text
			int fgColorIndex = headerInfo.getIndex("FGCOLOR");
			for (int j = start; j < end;j++) {
				String out = null;

				if(col == -1) {
					out = headerSummary.getSummary(headerInfo, j);
				} else {
					String [] summaryArray = headerSummary.getSummaryArray(headerInfo, j);
					if ((summaryArray != null) && (col < summaryArray.length))
						out = summaryArray[col];
				}

				if (out != null) {
					Color back = g.getColor();
					if ((geneSelection == null) || geneSelection.isIndexSelected(j)) {
						String [] strings = headerInfo.getHeader(j);
						if (fgColorIndex > 0) {
							g.setColor(TreeColorer.getColor(strings[fgColorIndex]));
						}
						g.drawString(out, 0, map.getMiddlePixel(j) + ascent / 2);
						if (fgColorIndex > 0) g.setColor(back);
					} else {
						g.setColor(Color.gray);
						g.drawString(out, 0, map.getMiddlePixel(j) + ascent / 2);
						g.setColor(back);
					}
				}
			}

		} else {		// some kind of blank default image?
			// backG.drawString("Select something already!", 0, offscreenSize.height / 2 );
		}
	}

	/**
	 * Set geneSelection
	 *
	 * @param geneSelection The TreeSelection which is set by selecting genes in the GlobalView
	 */
	public void setGeneSelection(TreeSelectionI geneSelection) {
		if (this.geneSelection != null)
			this.geneSelection.deleteObserver(this);
		this.geneSelection = geneSelection;
		this.geneSelection.addObserver(this);
	}

	public void setMap(MapContainer im) {
		if (map != null) {
			map.deleteObserver(this);
		}
		map = im;
		if (map != null) map.addObserver(this);
	}

	/** This method is called when the selection is changed. It causes the component to
	 * recalculate it's width, and call repaint.
	 */
	private void selectionChanged() {
		maxlength = 1;
		FontMetrics fontMetrics = getFontMetrics(new Font(face, style, size));
		int start = map.getIndex(0);
		int end =   map.getIndex(map.getUsedPixels());

		for (int j = start; j < end;j++) {
			int actualGene = j;
			String out = headerSummary.getSummary(headerInfo, actualGene);
			if (out == null) continue;
			int length = fontMetrics.stringWidth(out);
			if (maxlength < length) {
				maxlength = length;
			}
		}
		setPreferredSize(new Dimension(maxlength, map.getUsedPixels()));
		revalidate();
		repaint();
	}

	public UrlExtractor getUrlExtractor()
	{
		return urlExtractor;
	}

	// Observer
	public void update(Observable o, Object arg) {
		if (o == map) {
			selectionChanged(); // gene locations changed
		} else if (o == geneSelection) {
			selectionChanged(); // which genes are selected changed
		} else if(o == headerSummary) { //  annotation selection changed
			selectionChanged();
		} else {
			System.out.println("Textview got funny update!");
		}
	}
	// MouseListener
	public void mouseClicked(MouseEvent e) {
		if (urlExtractor == null) return;
		if (!urlExtractor.isEnabled()) return;
		// now, want mouse click to signal browser...
		int index = map.getIndex(e.getY());
		if (map.contains(index)) {
			final String url;
			if(col != -1)
			{
				url = urlExtractor.getUrl(index, headerInfo.getNames()[col]);
			}
			else
			{
				url = urlExtractor.getUrl(index);
			}
			LogBuffer.println("Opening url " + url);
			viewFrame.displayURL(url);
		}
	}

	// MouseMotionListener

	public void mousePressed(MouseEvent e) {
		dragging = true;


	}

	public void mouseDragged(MouseEvent e) {
		if (dragging) {
//	    int xoff = (e.getX() * (maxlength - offscreenSize.width)) / offscreenSize.width;
			// adjustScrollbar(xoff);
		}
	}

	public void mouseReleased(MouseEvent e) {
		dragging = false;
	}
	// KeyListener
	public void keyPressed(KeyEvent e) {
		int xoff = 0;//scrollbar.getValue();

		int c = e.getKeyCode();
		switch (c) {
			case KeyEvent.VK_UP:
				break;
			case KeyEvent.VK_DOWN:
				break;
			case KeyEvent.VK_LEFT:
				xoff -= scrollstep; break;
			case KeyEvent.VK_RIGHT:
				xoff += scrollstep; break;
			default:
				return;
		}
		adjustScrollbar(xoff);
	}
	// AdjustmentListener
	public void adjustmentValueChanged(AdjustmentEvent evt) {
		offscreenValid = false;
		repaint();
	}
	private void adjustScrollbar(int offset) {
		//	scrollbar.setValue(offset);
		offscreenValid = false;
		repaint();
	}


	//FontSelectable
	public String getFace() {
		return face;
	}
	public int getPoints() {
		return size;
	}
	public int getStyle() {
		return style;
	}

	public void setFace(String string) {
		if ((face == null) ||(!face.equals(string))) {
			face = string;
			if (root != null)
				root.setAttribute("face", face, d_face);
			setFont(new Font(face, style, size));
			repaint();
		}
	}

	public void setPoints(int i) {
		if (size != i) {
			size = i;
			if (root != null)
				root.setAttribute("size", size, d_size);
			setFont(new Font(face, style, size));
			repaint();
		}
	}

	public void setStyle(int i) {
		if (style != i) {
			style = i;
			if (root != null)
				root.setAttribute("style", style, d_style);
			setFont(new Font(face, style, size));
			repaint();
		}
	}



	public void bindConfig(ConfigNode configNode)
	{
		root = configNode;
		setFace(root.getAttribute("face", d_face));
		setStyle(root.getAttribute("style", d_style));
		setPoints(root.getAttribute("size", d_size));
		getHeaderSummary().bindConfig(root.fetchOrCreate("GeneSummary"));
	}

	private final int scrollstep = 5;
	private final String d_face = "Courier";
	private final int d_style = 0;
	private final int d_size = 12;

	protected HeaderInfo  headerInfo   = null;
	protected HeaderSummary headerSummary = new HeaderSummary();
	/** Setter for headerSummary */
	public void setHeaderSummary(HeaderSummary headerSummary) {
		this.headerSummary = headerSummary;
	}
	/** Getter for headerSummary */
	public HeaderSummary getHeaderSummary() {
		return headerSummary;
	}
	private ConfigNode root  = null;

	private String face;
	private int style;
	private int size;

	private TreeSelectionI geneSelection;
	private MapContainer map;
	private UrlExtractor urlExtractor;
	private int maxlength = 0;
	private int col;
	private boolean dragging = false;


	private JScrollPane scrollPane;

}
