/*
 * Worksheet.java
 *
 * Copyright (c) 2003, Oracle Corporation. All rights reserved. Oracle grants
 * you ("Licensee") a non-exclusive, royalty-free, worldwide license to use,
 * modify and redistribute this software in source and binary code form, provided
 * that (i) this copyright notice and license appear on all copies of the
 * software; (ii) Licensee does not utilize the software in a manner disparaging
 * to Oracle; and (iii) Licensee does not utilize the software in a manner that
 * violates the terms of any Licensee agreement with Oracle.
 */
package samples.javaclient.analyzer;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTargetListener;

import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;

import oracle.dss.crosstab.Crosstab;
import oracle.dss.crosstab.CrosstabDatabody;
import oracle.dss.crosstab.CrosstabPivotHeader;
import oracle.dss.dataSource.client.QueryClient;
import oracle.dss.dataSource.common.DataChangedEvent;
import oracle.dss.dataSource.common.Query;
import oracle.dss.dataSource.common.QueryAdapter;
import oracle.dss.dataView.ComponentHandle;
import oracle.dss.dataView.ControllerEvent;
import oracle.dss.dataView.ControllerListenerAdapter;
import oracle.dss.dataView.DataListenerAdapter;
import oracle.dss.dataView.Dataview;
import oracle.dss.dataView.DrillEvent;
import oracle.dss.dataView.PageEvent;
import oracle.dss.dataView.PagingControl;
import oracle.dss.dataView.PivotEvent;
import oracle.dss.graph.Graph;
import oracle.dss.util.DataSource;

/**
 * The Worksheet contains a dataview.  It is an MDI window that is displayed
 * in the desktop area of the application
 */
public class Worksheet extends JInternalFrame {
  JPanel m_pagePanel = new JPanel();
  Dataview m_dv = null;  
  String m_path = null;  // Path to dataview
  Analyzer m_parentFrame;  // Analyzer instance
  String m_title;
  boolean m_isDirty = false;
  public static final String INITIALIZING = "Initializing page...";
  private Vector m_listeners = new Vector();
  private Vector m_dropTargets = new Vector();
  private InternalFrameAdapter m_frameListener;
  private Graph m_graph = null;
  private Crosstab m_crosstab = null;
  
  public Worksheet(JFrame parent) {    
      super(INITIALIZING,
           true, //resizable
           true, //closable
           true, //maximizable
           true);//iconifiable
        //...Then set the window size or call pack...
      // setSize(400,400);

      m_parentFrame = (Analyzer) parent;
      m_pagePanel.setLayout(new GridLayout());
      getContentPane().setLayout(new BorderLayout());
      getContentPane().add(m_pagePanel, BorderLayout.CENTER);

      // Add a listener to check if the page is dirty when closing.  
      // If dirty, prompt the user to save
/*      m_frameListener = new InternalFrameAdapter() {
        public void internalFrameClosing(InternalFrameEvent e) {
          if (isDirty())
            System.out.println("IT's DIRTY!!!!!");
        }

        public void internalFrameClosed(InternalFrameEvent e) {
//          closePage();
        }
      };
      
      addInternalFrameListener(m_frameListener);
*/      
  }

  /**
   * Adds a dataview to the page.  Will automatically add listeners to the 
   * dataview for component changes and makes the data view a drop target.
   * @param dv The dataview object that should be added to the page
   */
  public void addDataview (Dataview dv) {
    addDataview(dv, true);
  }

  /**
   * Adds a dataview to the page.  
   * @param dv - The dataview object that should be added to the page
   *        addListeners - Specify whether listeners should be added to the dataview.  
   *                     Adding listeners also makes the data view a valid drop target
   */
  private void addDataview (Dataview dv, boolean addListeners) {
      m_dv = dv;

      // When a dataview is selected, notify the application - it must
      // be made the active dataview
      m_pagePanel.removeAll();
      m_pagePanel.add(dv);
      m_pagePanel.validate();
      m_pagePanel.repaint();

      if (addListeners) {
        // Keep track of the currently selected dataview
        // Also, update the application toolbar when the view is selected
        m_dv.addControllerListener(new ControllerListenerAdapter() {
          public void componentSelected(ControllerEvent p0) {
            ComponentHandle ch = p0.getComponentHandle();
            setActiveDataview((Dataview) p0.getSource());
            m_parentFrame.getToolBar().setDataView((Dataview) p0.getSource());
          }
        });
      
        // listen to events to track if the view is dirty
        // View events      
        m_dv.addDataListener(new DataListenerAdapter() {
          public void viewDrillRequested(DrillEvent e) {setDirty(true);}
          public void viewPageRequested(PageEvent e) {setDirty(true);}
          public void viewPivotRequested(PivotEvent e) {setDirty(true);}
        });

        // Query events
        Query query = (Query) m_dv.getDataSource();
        query.addQueryListener(new QueryAdapter() {
          public void dataChanged(DataChangedEvent e) {setDirty(true);}
        });      

        // Add drop target listener
        addDropTarget(dv);
      }
  }

  /**
   * Return the datasource that is being used by the worksheet
   */
  public DataSource getDataSource () {
    return m_dv.getDataSource();
  }  

  /**
   * Specify whether or not the worksheet has changed in any way - or is dirty
   * This is not really implemented yet.  Ideally, the application should prompt the user
   * to save changes if the worksheet has changed
   * @param isDirty Set the dirty flag
   */
  public void setDirty (boolean isDirty) {
    m_isDirty = isDirty;
  }

  /**
   * Returns a boolean indicating whether the worksheet has changed in any way.
   * @return True if dirty
   */
  public boolean isDirty () {
    return m_isDirty;
  }

  /**
   * Set the title for the Worksheet (e.g. "/My Reports/Sales Trends")
   * @param title Title for the worksheet
   */
  public void setTitle (String title) {
    m_title = title;
    super.setTitle(title);
  }

  /**
   * Return the worksheet title.  Note, this is also the path to the object in the
   * Catalog
   * @return Worksheet title
   */
  public String getTitle() {
    return m_title;
  }

  public JPanel getWorksheetPanel() {
    return m_pagePanel;
  }

  /**
   * Make the dataviews in the worksheet valid drop targets (for favorites and saved
   * selections
   */
  public void addDropTarget(Dataview dv) {
    // Need to get the components of the dataviews and add drop target
    // listeners to each of them

    /* 
     * For the Graph, make each part of the graph a drop target
     */ 
    AnalyzerDropTarget dropTarget = null;

    if (dv instanceof Graph) {
      Vector components = dv.getPhysicalComponents();

      for (int i = 0; i < components.size(); i++) {
        dropTarget = new AnalyzerDropTarget((Component) components.get(i), // component
            DnDConstants.ACTION_COPY_OR_MOVE, // actions
            (DropTargetListener) m_parentFrame); // DropTargetListener
        dropTarget.setAnalyzerTarget(AnalyzerDropTarget.DATAVIEW);
        dropTarget.setDataview(dv);
        dropTarget.setWorksheet(this);
        m_dropTargets.add(dropTarget);
      }
    }
    /*
     * Make the major parts of the crosstab a drop target
     */
    else {
      Crosstab crosstab = (Crosstab) dv;

      // Column header
      CrosstabPivotHeader header = (CrosstabPivotHeader) crosstab.getColumnHeader();
      dropTarget = new AnalyzerDropTarget(header.getGrid(),
                                  DnDConstants.ACTION_COPY_OR_MOVE, // actions
                                  (DropTargetListener) m_parentFrame); // DropTargetListener
      dropTarget.setAnalyzerTarget(AnalyzerDropTarget.DATAVIEW);                                  
      dropTarget.setDataview(dv);
      dropTarget.setWorksheet(this);
      m_dropTargets.add(dropTarget);

      // Row header
      header = (CrosstabPivotHeader) crosstab.getRowHeader();
      dropTarget = new AnalyzerDropTarget(header.getGrid(),
                                  DnDConstants.ACTION_COPY_OR_MOVE, // actions
                                  (DropTargetListener) m_parentFrame); // DropTargetListener
      dropTarget.setAnalyzerTarget(AnalyzerDropTarget.DATAVIEW);                                  
      dropTarget.setDataview(dv);
      dropTarget.setWorksheet(this);
      m_dropTargets.add(dropTarget);
      
      // Data body
      CrosstabDatabody body = (CrosstabDatabody) crosstab.getDatabody();
      dropTarget = new AnalyzerDropTarget(body.getGrid(),
                                  DnDConstants.ACTION_COPY_OR_MOVE, // actions
                                  (DropTargetListener) m_parentFrame); // DropTargetListener
      dropTarget.setAnalyzerTarget(AnalyzerDropTarget.DATAVIEW);
      dropTarget.setDataview(dv);
      dropTarget.setWorksheet(this);
      m_dropTargets.add(dropTarget);
      
      // Page controls and page control labels
      PagingControl pageControl = crosstab.getPagingControl();
      dropTarget = new AnalyzerDropTarget(pageControl,
                                  DnDConstants.ACTION_COPY_OR_MOVE, // actions
                                  (DropTargetListener) m_parentFrame); // DropTargetListener
      dropTarget.setAnalyzerTarget(AnalyzerDropTarget.DATAVIEW);
      dropTarget.setDataview(dv);
      dropTarget.setWorksheet(this);
      m_dropTargets.add(dropTarget);
      
      JLabel pageLabel = crosstab.getPagingControl().getLabel();
      dropTarget = new AnalyzerDropTarget(pageLabel,
                                  DnDConstants.ACTION_COPY_OR_MOVE, // actions
                                  (DropTargetListener) m_parentFrame); // DropTargetListener
      dropTarget.setAnalyzerTarget(AnalyzerDropTarget.DATAVIEW);                                  
      dropTarget.setDataview(dv);
      dropTarget.setWorksheet(this);
      m_dropTargets.add(dropTarget);
      
    }
  }

  /**
   * Clean up for the application.  Removes all listeners associated with the page and dataviews.
   */
  public void cleanUp() {
    // Clean up the listeners on the dataview and the query

    if (m_graph != null)
      m_graph.cleanUp();

    if (m_crosstab != null)
      m_crosstab.cleanUp();
//    m_dv.cleanUp();

    try {
      ((QueryClient)m_dv.getDataSource()).close();
    }
    catch (Exception e) {
      System.out.println("Unable to successfully clean-up query.");
    }

    // Remove drop target listners and drop targets
    for (int i = 0 ;i < m_dropTargets.size() ; i++)  {
      AnalyzerDropTarget dropTarget = (AnalyzerDropTarget) m_dropTargets.get(i);
      dropTarget.removeDropTargetListener((DropTargetListener) m_parentFrame);
      dropTarget.setDataview(null);
    }

    // Remove page listeners
    this.removeInternalFrameListener(m_frameListener);

    // Clear member variables reference 
    m_dv = null;
    m_graph = null;
    m_crosstab = null;
    m_listeners = null;
    m_frameListener = null;
    m_pagePanel = null;
    m_parentFrame = null;
    m_path = null;
    m_title = null;
    m_dropTargets = null;
 

  }

  /**
   * Returns the dataview in the worksheet that is currently in focus 
   * (this would be more use if the worksheet contained multiple dataviews)
   * @return the dataview that has focus
   */
  public Dataview getActiveDataview() {
    return m_dv;
  }

  /**
   * Specify the selected dataview in the worksheet
   */
  public void setActiveDataview(Dataview dataview) {
    m_dv = dataview;
  }

  /**
   * Set the path to the dataview (including its name)
   * For example:  "/My Reports/Sales Trends"
   */
  public void setActiveDataviewPath(String path) {
    setTitle(path);
  }

  /**
   * Return the path to the dataview (including its name)
   * For example:  "/My Reports/Sales Trends"
   */
  public String getActiveDataviewPath() {
    // The title and the path to the view are the same
    return getTitle();
  }

  /**
   * Change the view type of the current data view.  Valid values are 
   * Analyzer.VIEW_GRAPH or Analyzer.VIEW_CROSSTAB.  Keep a cached reference 
   * to the original dataview in order to preserve formatting and to achieve
   * fast performance when changing types
   * 
   * @param viewType The new view type
   */
  public void setDataviewType (String viewType) {
    // Only add listeners to the view if it is new 
    boolean addListeners = false;

    // Change the view type to a graph
    if (viewType.equalsIgnoreCase(Analyzer.VIEW_GRAPH)) {
      if (m_graph == null) {
        addListeners = true;         
        m_graph = new Graph();
      }          
      // Set the graph's data source to the active view's datasource
      m_graph.setDataSource(getActiveDataview().getDataSource());
      m_graph.setPagingControlVisible(getActiveDataview().getPagingControl().isVisible());
      m_graph.setDrillingEnabled(true);

      // Save the crosstab
      if (getActiveDataview() instanceof Crosstab)
       m_crosstab = (Crosstab) getActiveDataview();

      // Add the graph to the page
      addDataview(m_graph, addListeners);
    }
    else {
      // Change the view type to a crosstab
      if (m_crosstab == null) {
        addListeners = true;
        m_crosstab = new Crosstab();
      }
      // Set the crosstab data source to the active view's datasource
      m_crosstab.setDataSource(getActiveDataview().getDataSource());
      m_crosstab.setPagingControlVisible(getActiveDataview().getPagingControl().isVisible());
      
      // Save the graph
      if (getActiveDataview() instanceof Graph)
        m_graph = (Graph) getActiveDataview();

      // add the crosstab to the page
      addDataview(m_crosstab, addListeners);
    }
  }

  /**
   * Returns the type of dataview: Analyzer.VIEW_GRAPH or Analyzer.VIEW_CROSSTAB
   */
  public String getDataviewType () {
    if (m_dv instanceof oracle.dss.graph.Graph)
      return Analyzer.VIEW_GRAPH;
    else 
      return Analyzer.VIEW_CROSSTAB;
  }
}