package brn.gui.editors;

import gov.noaa.pmel.sgt.LineAttribute;
import gov.noaa.pmel.sgt.dm.SGTMetaData;
import gov.noaa.pmel.sgt.dm.SimpleLine;
import gov.noaa.pmel.sgt.swing.JClassTree;
import gov.noaa.pmel.sgt.swing.JPlotLayout;

import java.awt.Dimension;
import java.awt.image.BufferedImage;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;

import brn.gui.Activator;
import brn.gui.datasource.Source;
import brn.sim.data.AbstractDiagramData;
import brn.sim.data.CsvSerializer;
import brn.sim.data.XplotSerializer;

import com.sun.jimi.core.Jimi;
import com.sun.jimi.core.JimiException;

public class DataEditor extends EditorPart implements IPropertyChangeListener {

	public static final String ID = "brn.gui.editors.DataEditor";
  private static final int REFRESH_DELAY = 1000 /* ms */;
  private RefreshTimer timer;  //  @jve:decl-index=0:
  private boolean secondTry;

  private AbstractDiagramData data;
  private Composite top = null;
  private JPlotLayout pane;

  public DataEditor() {
		super();
    this.secondTry = false;

    timer = new RefreshTimer();
	}

  public boolean isRefresh() {
    return timer.isRunning();
  }

  public void refresh(boolean refresh) {
    if (refresh) {
      try {
        secondTry = false;
        refresh();
      } catch (CoreException e) {
        Activator.log(e);
        timer.stop();
        return;
      }

      timer.start();
    }
    else
      timer.stop();
  }

  public void resetZoom() {
    pane.resetZoom();
  }

  @SuppressWarnings("deprecation")
  public void openTree() {
    JClassTree ct = new JClassTree();
    ct.setModal(false);
    ct.setJPane(pane);
    ct.show();
  }


  @Override
  public void init(IEditorSite site, IEditorInput input) throws PartInitException {
    setSite(site);
    setInput(input);

    SimulatorItemInput dataInput = (SimulatorItemInput) getEditorInput();
    if (null == dataInput
        || null == dataInput.getSimulator()
        || !dataInput.getSimulator().isConnected())
      throw new PartInitException("Simulator in error state.");

    dataInput.getSimulator().addPropertyChangeListener(this);
    try {
      data = (AbstractDiagramData)
        dataInput.getSimulator().getContribution(dataInput.getId());
    } catch (CoreException e) {
      throw new PartInitException(e.getStatus());
    }
  }

  /**
   * Closes the editor programmatically.
   */
  public void close() {
    Display display = getSite().getShell().getDisplay();
    display.asyncExec(new Runnable() {
            public void run() {
                getSite().getPage().closeEditor(DataEditor.this, false);
            }
        });
  }

  @Override
  public void dispose() {
    if (null != timer)
      timer.stop();

    SimulatorItemInput input = (SimulatorItemInput) getEditorInput();
    if (null != input.getSimulator())
      input.getSimulator().removePropertyChangeListener(this);

    super.dispose();
  }

  @Override
  public void createPartControl(Composite parent) {
    String path = "";
    for (int i = 0; i < data.getPath().length; i++)
      path += data.getPath()[i] + ", ";

    setPartName(path);
    top = new Composite(parent, SWT.EMBEDDED);

    createPane();

    timer.start();
  }

  private void createPane() {
    SimulatorItemInput input = (SimulatorItemInput) getEditorInput();
    try {
      this.pane = createPane(data, input.getId());
    } catch (Exception e) {
      e.printStackTrace();
      return;
    }

    java.awt.Frame locationFrame = SWT_AWT.new_Frame(this.top);
    locationFrame.add(this.pane);
  }

  /**
   * Component initialization
   *
   * @param data
   */
  private static JPlotLayout createPane(AbstractDiagramData data, int dataId) throws Exception {

    double[] xValues = data.getX();
    double[] yValues = data.getY();
    if (null == xValues || xValues.length < 1)
      xValues = new double[]{0, 1};
    else if (xValues.length < 2)
      xValues = new double[]{0, xValues[0]};
    if (null == yValues || yValues.length < 1)
      yValues = new double[]{0, 1};
    else if  (yValues.length < 2)
      yValues = new double[]{0, yValues[0]};
    SimpleLine line = new SimpleLine(xValues, yValues, data.getTitle());
    line.setId(String.valueOf(dataId));
    line.setXMetaData(new SGTMetaData(data.getXLabel(), data.getXUnits()));
    line.setYMetaData(new SGTMetaData(data.getYLabel(), data.getYUnits()));

    /*
     * Create the layout without a Logo image and with the LineKey on the main
     * Pane object.
     */
    JPlotLayout pane = new JPlotLayout(line, data.getTitle(), null, false);
    pane.setAutoRange(true, true);

    /*
     * Add the time series to the layout and give a label for the legend.
     */
    pane.addData(line, new LineAttribute(data.getStyle()),
        line.getYMetaData().getName());
    /*
     * Change the layout's three title lines and place the Pane on the Applet.
     */
    pane.setTitles(data.getTitle(), data.getSubTitle(), "");

    pane.setAutoRange(true, true);
    pane.setBatch(true);

    return (pane);
  }

//  private static JPlotLayout createPane(Simulator simulator, int dataId) throws Exception {
//    if (!simulator.isConnected())
//      return null;
//
//    AbstractDiagramData data = simulator.getDriver().getData(dataId);
//    return createPane(data, dataId);
//  }

  public class RefreshTimer implements Runnable {
    private boolean stop = false;
    public void run() {
      try {
        refresh();
      } catch (CoreException e) {
        Activator.log(e);
        stop = true;
        return;
      }
      if (!stop)
        start();
    }
    public void start() {
      this.stop = false;
      getEditorSite().getShell().getDisplay().timerExec(REFRESH_DELAY, timer);
    }
    public void stop() {
      this.stop = true;
    }
    public boolean isRunning() {
      return !stop;
    }
  }

  protected void refresh() throws CoreException {
    if (!getEditorSite().getPage().isPartVisible(getSite().getPart()))
      return;

    SimulatorItemInput input = (SimulatorItemInput) getEditorInput();

    if (!input.getSimulator().isConnected())
      return;

    if (input.getSimulator().isPaused()) {
      if (secondTry) {
        // XXX pane is redrawn here because otherwise zooming wont work properly...
        pane.draw();
        return;
      }
      secondTry = true;
    } else
      secondTry = false;

    data = (AbstractDiagramData) input.getSimulator().getContribution(input.getId());
    // TODO test if changed this.data.getXArray();

    pane.clear(String.valueOf(input.getId()));

    double[] xValues = data.getX();
    double[] yValues = data.getY();
    if (null == xValues || xValues.length < 1)
      xValues = new double[]{0, 1};
    else if (xValues.length < 2)
      xValues = new double[]{0, xValues[0]};
    if (null == yValues || yValues.length < 1)
      yValues = new double[]{0, 1};
    else if  (yValues.length < 2)
      yValues = new double[]{0, yValues[0]};
    SimpleLine line = new SimpleLine(xValues, yValues, data.getTitle());
    line.setId(String.valueOf(input.getId()));
    line.setXMetaData(new SGTMetaData(data.getXLabel(), data.getXUnits()));
    line.setYMetaData(new SGTMetaData(data.getYLabel(), data.getYUnits()));

    pane.addData(line, new LineAttribute(data.getStyle()),
        line.getYMetaData().getName());
    pane.draw();
  }

  @Override
  public void setFocus() {
    top.setFocus();
  }

  @Override
  public boolean isDirty() {
    return false;
  }

  @Override
  public boolean isSaveAsAllowed() {
    return false;
  }

  @Override
  public void doSave(IProgressMonitor monitor) {
  }

  @Override
  public void doSaveAs() {
  }

  public void propertyChange(PropertyChangeEvent event) {
    if (event.getProperty().equals(Source.CONNECTED)
      ||event.getProperty().equals(Source.DATASOURCE_DISPOSED)) {
      SimulatorItemInput input = (SimulatorItemInput) getEditorInput();
      if (null == input.getSimulator()
          ||!input.getSimulator().isConnected()) {
        if (null != input.getSimulator())
          input.getSimulator().removePropertyChangeListener(this);
        close();
      }
    }
  }

  public void saveText() {
    Shell shell = getSite().getShell();
    FileDialog dialog = new FileDialog(shell, SWT.SAVE);
    dialog.setFilterNames (new String [] {"XPlot Files", "All Files (*.*)"});
    dialog.setFilterExtensions (new String [] {"*.xpl", "*.*"}); //Windows wild cards

    String fileName = dialog.open();
    if (null == dialog.getFileName() || dialog.getFileName().length() == 0)
      return;

    if (!fileName.endsWith(".xpl"))
      fileName += ".xpl";

    try {
      XplotSerializer seri =  new XplotSerializer(data, "green");
      seri.saveToFile(fileName);
    } catch (Exception e) {
      e.printStackTrace();
      MessageBox errorDlg = new MessageBox(shell, SWT.OK);
      errorDlg.setText("Error");
      errorDlg.setMessage(e.getMessage());
      errorDlg.open();
    }
  }
  
  public void saveCvs() {
    Shell shell = getSite().getShell();
    FileDialog dialog = new FileDialog(shell, SWT.SAVE);
    dialog.setFilterNames (new String [] {"CSV Files", "All Files (*.*)"});
    dialog.setFilterExtensions (new String [] {"*.csv", "*.*"}); //Windows wild cards

    String fileName = dialog.open();
    if (null == dialog.getFileName() || dialog.getFileName().length() == 0)
      return;

    if (!fileName.endsWith(".csv"))
      fileName += ".csv";

    try {
      CsvSerializer seri =  new CsvSerializer(data);
      seri.saveToFile(fileName);
    } catch (Exception e) {
      e.printStackTrace();
      MessageBox errorDlg = new MessageBox(shell, SWT.OK);
      errorDlg.setText("Error");
      errorDlg.setMessage(e.getMessage());
      errorDlg.open();
    }
  }

  public void saveImage() {
    Shell shell = getSite().getShell();
    FileDialog dialog = new FileDialog(shell, SWT.SAVE);
    dialog.setFilterNames (new String [] {"Text Files", "All Files (*.*)"});
    dialog.setFilterExtensions (new String [] {"*.png", "*.*"}); //Windows wild cards

    String fileName = dialog.open();
    if (null == dialog.getFileName() || dialog.getFileName().length() == 0)
      return;

    if (!fileName.endsWith(".png"))
      fileName += ".png";


    try {
      saveImage(fileName);
    } catch (Exception e) {
      e.printStackTrace();
      MessageBox errorDlg = new MessageBox(shell, SWT.OK);
      errorDlg.setText("Error");
      errorDlg.setMessage(e.getMessage());
      errorDlg.open();
    }
  }

  /**
   * Saves the diagram into the specified file
   *
   * @param sFileName
   * @throws JimiException
   */
  public void saveImage(String sFileName) throws Exception {
    Dimension dim = new Dimension(1400, 1050);
    boolean visible = getSite().getPage().isEditorAreaVisible();
    if (!visible) {
      pane.setSize(dim.width, dim.height);
      pane.validate();
    }

    Dimension d = pane.getSize();
    BufferedImage img = new BufferedImage(d.width, d.height,
            BufferedImage.TYPE_INT_RGB);
    pane.draw(img.createGraphics(), d.width, d.height);
    Jimi.putImage(img, sFileName);

    if (!visible) {
      dispose();
    }
  }

//
//  public static void saveImage(JistAdapter adapter, int dataId, String sFileName)
//      throws Exception {
//    Dimension dim = new Dimension(1400, 1050);
//    JPlotLayout pane = createPane(adapter, dataId);
//    pane.setVisible(true);
//    pane.setSize(dim.width, dim.height);
////  pane.setBatch(false);
////    pane.setDoubleBuffered(false);
//
//    Dimension d = pane.getSize();
//    BufferedImage img = new BufferedImage(d.width, d.height,
//            BufferedImage.TYPE_INT_RGB);
//    pane.draw(img.createGraphics(), d.width, d.height);
//    Jimi.putImage(img, sFileName);
//  }

//  public void dataPrint() {
//    Color saveColor;
//    if (null == pageFormat)
//      pageFormat = PrinterJob.getPrinterJob().defaultPage();
//
//    PrinterJob printJob = PrinterJob.getPrinterJob();
//    printJob.setPrintable(pane, pageFormat);
//    printJob.setJobName("Grid Demo");
//    if (printJob.printDialog()) {
//      try {
//        saveColor = pane.getBackground();
//        if (!saveColor.equals(Color.white)) {
//          pane.setBackground(Color.white);
//        }
//        pane.setPageAlign(AbstractPane.TOP, AbstractPane.CENTER);
//        RepaintManager currentManager = RepaintManager.currentManager(pane);
//        currentManager.setDoubleBufferingEnabled(false);
//        printJob.print();
//        currentManager.setDoubleBufferingEnabled(true);
//        pane.setBackground(saveColor);
//      } catch (PrinterException pe) {
//        System.out.println("Error printing: " + pe);
//      }
//    }
//  }
//
//  public void dataLayout() {
//    if (null == pageFormat)
//      pageFormat = PrinterJob.getPrinterJob().defaultPage();
//
//    PrinterJob pj = PrinterJob.getPrinterJob();
//    pageFormat = pj.pageDialog(pageFormat);
//  }

}
