/*
** Luxor - XML User Interface Language (XUL) Toolkit
** Copyright (c) 2001, 2002 by Gerald Bauer
**
** This program is free software.
**
** You may redistribute it and/or modify it under the terms of the GNU
** General Public License as published by the Free Software Foundation.
** Version 2 of the license should be included with this distribution in
** the file LICENSE, as well as License.html. If the license is not
** included with this distribution, you may find a copy at the FSF web
** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the
** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA.
**
** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
** REDISTRIBUTION OF THIS SOFTWARE.
**
*/

package luxor.swing.datagrid;

import java.util.*;
import javax.swing.table.*;
import org.jaxen.JaxenException;
import org.jaxen.VariableContext;
import org.jaxen.jdom.XPath;
import org.jdom.*;
import luxor.core.*;
import luxor.core.widget.*;
import luxor.status.*;

/**
 *  note: this code is expirimental it is currently extremely inefficient and
 *  crude as some concepts still needs to worked out it will improve
 *  substantially over the next couple of months
 */

public class XmlXPathTableModel extends AbstractTableModel
       implements VariableContext
{
   static Logger T = Logger.getLogger( XmlXPathTableModel.class );

   String _columnName[] = {};
   XPath _columnSelect[] = {};
   /*
    *  public Class  getColumnClass( int i ) { return _columnClass[i]; }
    */
   int _currentRow;

   List _data;
   // aka rows/records in xml
   int _rowCount;

   public XmlXPathTableModel( DataGridDef def, Document doc )
   {
      try
      {
         XPath rowSelect = def.getSelect( "/*/*" );
         T.debug( "selecting rows from XML data using XPath expr " + rowSelect.toString() );

         _data = rowSelect.selectNodes( doc );
      }
      catch( JaxenException jex )
      {
         Xul.error( "failed to select table rows using XPath expr: " + jex.toString() );
         _data = Collections.EMPTY_LIST;
      }

      _rowCount = _data.size();
      T.debug( _rowCount + " row(s) selected" );

      List colDefs = def.getColGroupDef().getColDefs();
      int colCount = colDefs.size();

      _columnName = new String[colCount];
      _columnSelect = new XPath[colCount];

      for( int i = 0; i < colCount; i++ )
      {
         ColDef colDef = ( ColDef ) colDefs.get( i );

         _columnName[i] = colDef.getHeading( "" + ( i + 1 ) );
         _columnSelect[i] = colDef.getSelect( "*[" + ( i + 1 ) + "]" );
         // add XPath Variable Context to allow cross-referencing
         _columnSelect[i].setVariableContext( this );
      }
   }

   public void setValue( Object obj, int row, int col ) { }

   public int getColumnCount()
   {
      return _columnName.length;
   }

   public int getColumnIndex( String name )
   {
      for( int i = 0; i < _columnName.length; i++ )
      {
         if( _columnName[i].equalsIgnoreCase( name ) )
            return i;
      }
      return -1;
      // not found
   }

   public String getColumnName( int i )
   {
      return _columnName[i];
   }

   public int getRowCount()
   {
      return _rowCount;
   }


   public Object getValueAt( int row, int col )
   {
      // todo: check for out of bound exception

      _currentRow = row;
      // keep track of current row for XPath-VariableContext

      Object rowObj = _data.get( row );
      T.debug( "row[" + ( row + 1 ) + "]:" + rowObj.getClass().getName() + "=" + rowObj.toString() );

      Object colObj;

      try
      {
         colObj = _columnSelect[col].evaluate( rowObj );
         T.debug( "col[" + ( col + 1 ) + "]:" + colObj.getClass().getName() + "=" + colObj.toString() );

         if( colObj instanceof List )
         {
            List nodes = ( List ) colObj;

            T.debug( "nodes.size()=" + nodes.size() );

            if( nodes.size() == 0 )
               colObj = "";
            else
            {
               Object node = nodes.get( 0 );

               String clazz = node.getClass().getName();
               String value = node.toString();

               T.debug( clazz + "[0]=" + value );

               if( node instanceof Element )
               {
                  colObj = ( ( Element ) node ).getTextTrim();
               }
               else
                  colObj = node.toString();
            }
         }
      }
      catch( JaxenException jex )
      {
         Xul.error( "failed to select column " + ( col + 1 ) + " in row " + ( row + 1 ) + " using XPath expr: " + jex.toString() );
         colObj = "";
      }

      return colObj;
   }

   /**
    *  XPath VariableContext provider (aka variable lookup/resolver)
    */
   public Object getVariableValue(
         String namespaceURI,
         String prefix,
         String localName )
   {
      int col = getColumnIndex( localName );

      // todo: should i return empty string instead of null?
      if( col == -1 )
         return null;
      else
         return getValueAt( _currentRow, col );
   }

   public boolean isCellEditable( int row, int col )
   {
      return false;
   }
}