/*
 * @(#)BIBeanDataAccessAdapter.java
 *
 * Copyright 2001-2002 by Oracle Corporation,
 * 500 Oracle Parkway, Redwood Shores, California, 94065, U.S.A.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information
 * of Oracle Corporation.
 */

package oracle.jbo.html.jsp.graph;


import java.util.ArrayList;
import oracle.dss.util.ColumnOutOfRangeException;
import oracle.dss.util.CubeDataDirector;
import oracle.dss.util.DataAccessAdapter;
import oracle.dss.util.DataAvailableEvent;
import oracle.dss.util.DataChangedEvent;
import oracle.dss.util.DataDirector;
import oracle.dss.util.DataDirectorException;
import oracle.dss.util.DataDirectorListener;
import oracle.dss.util.DataMap;
import oracle.dss.util.EdgeOutOfRangeException;
import oracle.dss.util.LayerMetadataMap;
import oracle.dss.util.LayerOutOfRangeException;
import oracle.dss.util.MetadataMap;
import oracle.dss.util.RelationalDataDirector;
import oracle.dss.util.RowOutOfRangeException;
import oracle.dss.util.SliceOutOfRangeException;

/**
 * Internal class used to define data source of BI Graph bean.
 * 
 */
class BIBeanDataAccessAdapter
    extends  DataAccessAdapter
    implements RelationalDataDirector, CubeDataDirector
{

    private static final String mEmptyString = "";
    
    private int pageCount;
    
    private int currentPage;
    
    protected DataDirectorListener mListener = null;

    GraphModelBase mOwner;

    ArrayList listeners = new ArrayList(5);
    
    BIBeanDataAccessAdapter(GraphModelBase owner)
    {

        mOwner = owner;

        currentPage = 0;
    }
    
    
    /**
     * Pivots data. Operations include:
     * <ul>
     * <li>Moving dimensions or dimension members from one edge to another.</li>
     * <li>Moving dimensions or dimension members from one location on an
     *     edge to another location on the same edge.</li>
     * <li>Swapping the locations of two dimensions.</li>
     * <li>Swapping two edges.
     * </ul>
     *
     * @param fromEdge  The edge to pivot from.
     * @param toEdge    The edge to pivot to.
     * @param fromLayer The layer to pivot from. The layer identifies the
     *                  location of the dimension or dimension member; 0 is the
     *                  outer-most dimension on the edge.
     * @param toLayer   The layer to pivot to.
     * @param flags     Constant that indicates the type of pivot to perform.
     *                  The constants begin with PIVOT_ in this interface.
     *
     * @return <code>true</code> if the pivot is successful,
     *         <code>false</code> if not.
     * @throws EdgeOutOfRangeException If either edge is too
     *                  large.
     * @throws LayerOutOfRangeException If either layer is negative or
     *                  too large.
     * @throws DataDirectorException If a data provider error occurs.
     *
     * @status Needs change API rework
     */
    public boolean pivot(int fromEdge, int toEdge, int fromLayer, 
            int toLayer, int flags) 
         throws EdgeOutOfRangeException, LayerOutOfRangeException, 
         DataDirectorException 
    {
        return false;
    }

    /**
     * Drills in the data, from a single member.
     *
     * @param edge   The edge to drill.
     * @param layer  The layer to drill. The layer identifies the
     *                  location of the dimension or dimension member; 0 is the
     *                  outer-most dimension on the edge.
     * @param slice  The slice to drill. The slice is zero-based. Each
     *                  dimension member in the innermost dimension has a
     *                  unique slice. In outer dimensions, any slice that the
     *                  outer dimension spans can be used.
     * @param flags  Constant that indicates the type of drill.
     *                  The constants begin with DRILLABLE_ in this interface.
     *
     * @return <code>true</code> If drilling is successful,
     *         <code>false</code> if not.
     *
     * @throws EdgeOutOfRangeException If <code>edge</code> is too large.
     * @throws LayerOutOfRangeException If <code>layer</code> is negative or
     *                  too large.
     * @throws SliceOutOfRangeException If <code>slice</code> is negative or
     *                  too large.
     * @throws DataDirectorException If a data provider error occurs.
     *
     * @status Needs change API change
     */
    public boolean drill(int edge, int layer, int slice, int flags) 
           throws EdgeOutOfRangeException, LayerOutOfRangeException, 
           SliceOutOfRangeException, DataDirectorException 
    {
        return true;
    }
    
    /**
     * Retrieves the total number of members on the given edge.
     * cursor.
     *
     * @param   edge Edge of interest.
     * @return   The total number of members on the given edge.
     *
     * @status Needs change API change
     */
    public int getEdgeExtent(int edge) 
           throws EdgeOutOfRangeException 
    {
        switch (edge) {
            case DataDirector.COLUMN_EDGE:
                return mOwner.getColumnCount();
            case DataDirector.ROW_EDGE:
                return (int) mOwner.getRowCount();
            default:
                return pageCount;
        }
    }
    
    /**
     * Return the total number of edges in the data source. 
     * Note: the views will consider all edges beyond 0 and 1 (column/
     * row) to be page edges, and some of the methods retrieving page
     * counts, etc., may involve view calculations from more basic data
     * source information. The views assume that the data source will
     * ascribe column/row meaning to the first two edges on any query.
     * 
     * @return the total number of pages of data to display
     */
    public int getEdgeCount() 
    {
        return 3;
    }

    /**
     * Retrieves a data value for the specified row and column intersection.
     *
     * @param row The row to get.
     * @param col The column to get.
     * @param type Type of data to return, such as formatted or unformatted.
     *             Valid <code>type</code> values are defined in the DataMap.
     *
     * @return The specified type of information for the specified row and
     *         column location.
     *
     * @throws RowOutOfRangeException If <code>row</code> is negative or too
     *                                large.
     * @throws ColumnOutOfRangeException If <code>column</code> is negative or
     *                                too large.
     *
     * @see DataMap
     *
     * @status Documented
     */
    public Object getValue(int aRow, int aColumn, String type) 
        throws RowOutOfRangeException, ColumnOutOfRangeException 
    {
        return mOwner.getValue(aRow, aColumn);
    }


    public boolean setValue(Object aValue,
        int    aRow,           // zero-based row
        int    aColumn,        // zero-based column
        String     type)          // what type of value to set: ignored for now - data only
         throws RowOutOfRangeException, ColumnOutOfRangeException
    {
        return false; // no set values allowed
    }

    /**
     * Retrieves the label for the specified column.
     *
     * @param   edge Edge of interest.
     * @param slice The slice whose label is desired.
     * @param type A constant that specifies the kind of metadata that you want.
     *             Valid <code>type</code> values are defined in the MetadataMap.
     *
     * @return The label (or metadata) for the location on the specified edge.
     *
     * @throws EdgeOutOfRangeException If <code>edge</code> is out of range.
     * @throws SliceOutOfRangeException If <code>slice</code> is negative or
     *         too large.
     *
     * @status Needs change API change
     */
    public Object getSliceLabel(int edge, int slice, String type) 
        throws EdgeOutOfRangeException, SliceOutOfRangeException 
    {
        switch (edge) {
            case DataDirector.COLUMN_EDGE:
                return mOwner.getColumnLabel(slice);
            case DataDirector.ROW_EDGE:
                return mOwner.getRowLabel(slice);
            case DataDirector.PAGE_EDGE:
            default:
                if (slice < 0 || slice >= pageCount)
                    throw new SliceOutOfRangeException(slice, pageCount);
                return mEmptyString;
        }            
    }

    /**
     * Retrieves the number of the current slice.
     * The number that this method returns is not the regular index of the
     * page dimension. Instead, page numbers begin at 1 and are incremented
     * as in the following example:
     * <p>
     * Suppose that you have a Time dimension and a City dimension on the page
     * edge. Suppose the City dimension has three members.
     * The first five pages are as follows:
     * <P>
     * <ul><li>0. Time member 0; City member 0</li>
     *     <li>1. Time member 0; City member 1</li>
     *     <li>2. Time member 0; City member 2</li>
     *     <li>3. Time member 1; City member 0</li>
     *     <li>4. Time member 1; City member 1</li>
     * </ul>
     *
     * @return The current slice of the edge.
     * @throws EdgeOutOfRangeException If <code>edge</code> is out of range.
     *
     * @status Needs change API change
     */
    public int getEdgeCurrentSlice(int edge) 
          throws EdgeOutOfRangeException
    {
        return currentPage;
    }

    /**
     * Changes the current slice of data on the given edge.
     *
     * @param edge The edge on which to make the change.
     * @param slice The slice to make current. 
     * Page numbers begin at zero and are incremented as in the following example:
     * <p>
     * Suppose that you have a Time dimension and a City dimension on the page
     * edge. Suppose the City dimension has three members.
     * The first five pages are as follows:
     * <P>
     * <ul><li>0. Time member 0; City member 0</li>
     *     <li>1. Time member 0; City member 1</li>
     *     <li>2. Time member 0; City member 2</li>
     *     <li>3. Time member 1; City member 0</li>
     *     <li>4. Time member 1; City member 1</li>
     * </ul>
     *
     * @return <code>true</code> if the page change is successful,
     *         <code>false</code> if not.
     *
     * @throws EdgeOutOfRangeException If <code>edge</code> is too large.
     * @throws SliceOutOfRangeException If <code>slice</code> is too large.
     * @throws DataDirectorException If a data provider error occurs.
     *
     * @status Needs change API change
     */
    public boolean changeEdgeCurrentSlice(int edge, int slice) 
         throws EdgeOutOfRangeException, SliceOutOfRangeException, 
        DataDirectorException 
    {
        if (slice < 0 || slice >= pageCount)
            return false;
        currentPage =  slice;
        return true;
    }

    /**
     * Retrieves the number of layers on the specified edge.
     *
     * @param edge A constant that represents the edge of interest.
     *             The constants are defined in the DataDirector implementation.
     *
     * @return The number of layers on the specified edge.
     *
     * @throws EdgeOutOfRangeException If <code>edge</code> is out of range.
     * @status Needs change API change
     */
    public int getLayerCount(int edge) 
          throws EdgeOutOfRangeException
    {
        if (edge==DataDirector.PAGE_EDGE)
            return 0;
        else
            return 1;
    }

    /**
     * Retrieves the number of logical layers at the specified location on the
     * specified edge.
     * This method is useful in cases of asymmetry where the dimensions
     * on an edge do not all span the same layers.
     *
     * @param edge A constant that represents the edge of interest. Constants
     *             are defined in the DataDirector implementation.
     * @param slice The slice that identifies a location along the edge of
     *              interest. The slice is zero-based. Each
     *                  member in the innermost layer has a
     *                  unique slice. In outer layers, any slice that the
     *                  outer layer spans can be used.
     *
     * @return    The number of logical layers at the specified location on the
     *            specified edge.
     *
     * @throws EdgeOutOfRangeException If <code>edge</code> is out of range.
     * @throws SliceOutOfRangeException If <code>slice</code> is negative or too
     *              large.
     *
     * @status Needs change API change
     */
    public int getSliceMemberCount(int edge, int slice) 
        throws EdgeOutOfRangeException, SliceOutOfRangeException 
    {
        if (edge==DataDirector.PAGE_EDGE)
            return 0;
        else
            return 1;
    }


    /**
     * Retrieves a piece of metadata for a dimension member.
     * 
     * @param edge A constant that represents the edge of interest.
     *             The constants are defined in the DataDirector implementation.
     * @param layer The layer of the member of interest.
     *              Valid values are zero to total layers at the specified
     *              slice.
     * @param slice The location along the edge.
     *              The slice is zero-based. Each
     *                   member in the innermost layer has a
     *                  unique slice. In outer layers, any slice that the
     *                  outer member spans can be used.
     * @param type A constant that specifies the kind of metadata that you want.
     *             Valid <code>type</code> values are defined in the MetadataMap.
     *
     * @return The requested metadata.
     *
     * @throws LayerOutOfRangeException If <code>layer</code> is negative or
     *              too large.
     * @throws SlieOutOfRangeException If <code>slice</code> is negative or
     *              too large.
     *
     * @status Needs change API change
     */
    public Object getMemberMetadata(int edge, int layer, int slice, String type)
       throws EdgeOutOfRangeException, LayerOutOfRangeException, 
       SliceOutOfRangeException 
    {
        if (type.equals(MetadataMap.METADATA_DRILLSTATE)) {
            switch ((int)slice) {
                case 0:
                    return new Integer(1);
                case 1:
                    return new Integer(2);
            }
            return new Integer(0);
        }
        if (type.equals(MetadataMap.METADATA_INDENT)) 
            return new Integer((int)slice);

        Object obj = null;
        switch (edge) {
            case DataDirector.COLUMN_EDGE:
                obj = mOwner.getColumnLabel(slice);
            break;
            case DataDirector.ROW_EDGE:
                obj = mOwner.getRowLabel(slice);
            break;
            case DataDirector.PAGE_EDGE:
                obj = mEmptyString;
            break;
        };
        return obj;            
    }
            
    /**
     * Retrieves the number of slices that a member spans.
     * Views use this method to determine the width of a member
     * in a column header or the height of a member in
     * a row header when not in outline form.
     *
     * @param edge A constant that represents the edge of interest.
     *             The constants are defined in the DataDirector implementation.
     * @param layer The layer of the dimension of interest.
     *              Valid values are zero to total layer at the specified
     *              slice.
     * @param slice The location along the edge.
     *              The slice is zero-based. Each
     *                  member in the innermost layer has a
     *                  unique slice. In outer layers, any slice that the
     *                  outer member spans can be used.
     *
     * @return The number of slices that the member spans at the
     *         specified location.
     *
     * @throws EdgeOutOfRangeException If <code>edge</code> is too large.
     * @throws LayerOutOfRangeException If <code>layer</code> is negative or
     *               too large
     * @throws SliceOutOfRangeException If <code>slice</code> is negative or
     *               too large
     *
     * @see #getMemberStartSlice
     *
     * @status Needs change API change
     */
    public int getMemberExtent(int edge, int depth, int slice) 
       throws EdgeOutOfRangeException, LayerOutOfRangeException, 
       SliceOutOfRangeException 
    {
        return 1;
    }

    /**
     * Retrieves the number of layers that a member spans at the specified
     * location on the specified edge.
     * On the column edge, this is the number of heading rows that the specified
     * member spans.
     * On the row edge, this is the number of heading columns that the specified
     * member spans.
     * <P>
     * This method is useful only in cases of asymmetry where the members
     * on an edge do not all span one layer and have a depth of 1.
     * Normally, all members have a member depth of 1.
     *
     * @param edge  A constant that represents the edge of interest.
     *             The constants are defined in the DataDirector implementation.
     * @param layer The starting layer of the member, as returned by
     *              <code>getMemberStartLayer</code>.
     * @param slice The location along the edge.
     *              The slice is zero-based. Each
     *                  member in the innermost layer has a
     *                  unique slice. In outer layers, any slice that the
     *                  outer member spans can be used.
     *
     * @return    The number of layers that the specified member spans.
     *
     * @throws EdgeOutOfRangeException If <code>edge</code> is too large.
     * @throws LayerOutOfRangeException If <code>layer</code> is negative or
     *            too large.
     * @throws SliceOutOfRangeException If <code>slice</code> is negative or
     *            too large.
     *
     * @status Needs change API change
     */
    public int getMemberDepth(int edge, int layer, int slice) 
      throws EdgeOutOfRangeException, LayerOutOfRangeException, 
      SliceOutOfRangeException
    {
        return 1;
    }

    /**
     * Retrieves the starting slice of a member that spans a number of layers 
     * on the specified edge.
     * <P>
     * This method is useful only in cases of asymmetry where the members
     * on an edge do not all span one layer.
     * Normally, all members have a member start layer equal to their layer.
     *
     * @param edge  A constant that represents the edge of interest.
     *             The constants are defined in the DataDirector implementation.
     * @param layer The layer of the member
     * @param slice The location along the edge.
     *              The slice is zero-based. Each
     *                  member in the innermost dimension has a
     *                  unique slice. In outer layers, any slice that the
     *                  outer member spans can be used.
     *
     * @return    The layer at which the specified member starts its layer span.
     *
     * @throws EdgeOutOfRangeException If <code>edge</code> is too large.
     * @throws LayerOutOfRangeException If <code>layer</code> is negative or
     *            too large.
     * @throws SliceOutOfRangeException If <code>slice</code> is negative or
     *            too large.
     *
     * @status New
     */
     public int getMemberStartLayer(int edge, int layer, int slice) 
        throws EdgeOutOfRangeException, LayerOutOfRangeException, 
              SliceOutOfRangeException 
    {
        return layer;
    }

    /**
     * NEW
     * Register a listener to the data source for changes.
     *
     * @param l listener
     */
    public void addDataDirectorListener(DataDirectorListener l)
    {
		if ( l != null)
		{
			listeners.add(l);

			l.viewDataAvailable(new DataAvailableEvent(this, this));
		}
    }

    /**
     * NEW
     * Remove a listener from the data source.
     *
     * @param l listener
     */
    public void removeDataDirectorListener(DataDirectorListener l) 
    {
		if (l != null)
		{
			listeners.remove(l);
		}
    }


	public boolean refresh() 
	       throws DataDirectorException 
	{ 
		DataChangedEvent event = new DataChangedEvent(this, this, true,  true, 
														  
													  true, true) ;
		
		{
			for (int i=0; i < listeners.size(); i++)
			{
				DataDirectorListener l = (DataDirectorListener)listeners.get(i);

				l.viewDataChanged(event);

			}
		}

		return true;
	}

    public DataMap getSupportedDataMap()
    {
        String supported[] = {DataMap.DATA_UNFORMATTED,
                             DataMap.DATA_FORMATTED};
        return (new DataMap(supported));
    }
    
    public MetadataMap getSupportedMetadataMap()
    {
        String supported[] =  { MetadataMap.METADATA_LONGLABEL,
                               MetadataMap.METADATA_MEDIUMLABEL,
                               MetadataMap.METADATA_SHORTLABEL};
        return (new MetadataMap(supported));
    }
    
    public LayerMetadataMap getSupportedLayerMetadataMap()
    {
         
        String supported[] = { LayerMetadataMap.LAYER_METADATA_LONGLABEL,
                              LayerMetadataMap.LAYER_METADATA_MEDIUMLABEL,
                              LayerMetadataMap.LAYER_METADATA_SHORTLABEL};
        return (new LayerMetadataMap(supported));
    } 
    


}
