/*
 * Created on 04-Oct-2003
 *
 * To change the template for this generated file go to
 * Window>Preferences>Java>Code Generation>Code and Comments
 */
package com.k_int.AdminApp.gui.RecordView;

import javax.swing.table.AbstractTableModel;

import javax.swing.JTable;
import java.util.Set;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.jxpath.JXPathContext;
import com.k_int.AdminApp.gui.AdminControllerComponent;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.*;

/**
 * @author Ian Ibbotson (ian.ibbotson@k-int.com )
 *
 * A class that acts as a bridge between a Set attribute of
 * an entity and a JTable that shows the rows of that set.
 *
 * ToDo: CollectionComponentModel superclass with List,Set common methods
 */
public class SetComponentModel extends AbstractTableModel implements RecordModelListener
{
    private static Logger cat = Logger.getLogger("com.k_int.AdminApp.gui.RecordView.SetComponentModel");
  private String access_path;
  private String reciprocal_property_name;
  private String[] column_attr_paths;
  private String[] column_headings;
  private Set data = null;
  private Object[] rows = null;
  private boolean editable = false;
  private Object record;
  private AbstractRecordController controller;
  private boolean auto_edit_new_object = true;
  private JTable the_table;
  private int tab_heading_row=-1;
  private SimpleDateFormat df = new SimpleDateFormat();
  
   
  public SetComponentModel(String access_path,
                           String reciprocal_property_name,
                           String[] column_attr_paths,
                           String[] column_headings,
                           boolean auto_edit_new_object)
  {
    this.access_path = access_path;
    this.reciprocal_property_name = reciprocal_property_name;
    this.column_attr_paths = column_attr_paths;
    this.column_headings = column_headings;
    this.auto_edit_new_object = auto_edit_new_object;
    cat.fine("New set component "+access_path+","+column_attr_paths+","+column_headings);
  }
  
  
  public void setEditorTitleSuffixRow(int table_row)
  {
      tab_heading_row = table_row;
  }
  
  public void setDateFormat(String date_format)
  {
      df=new SimpleDateFormat(date_format);
  }

  /* (non-Javadoc)
   * @see com.k_int.AdminApp.gui.RecordView.RecordModelListener#recordChanged(java.lang.Object, boolean)
   */
  public void recordChanged(Object record, boolean editable)
  {
    cat.finest("SetComponentModel::recordChanged "+record);
    cat.finest("Access path is "+access_path);
    this.record = record;
    this.editable = editable;

    // ToDo: Badly need to catch the exception here and re-throw it in a sensible way.
    data = (Set)JXPathContext.newContext(record).getValue(access_path);

    cat.finest("Result was "+data);
    
    if ( data != null )
      rows = data.toArray();
    else
      rows = null;
      
      cat.finest("access_path "+access_path);
      cat.finest("reciprocal access path"+reciprocal_property_name);
   
    this.fireTableDataChanged();
  }
  

  public void recordSetChanged()
  {
    if ( data != null )
      rows = data.toArray();
    else
      rows = null;

    this.fireTableDataChanged();
  }

  /* (non-Javadoc)
   * @see com.k_int.AdminApp.gui.RecordView.RecordModelListener#synchronizeViewToModel()
   */
  public void synchronizeViewToModel()
  {
    cat.fine("SetComponentModel::synchronizeViewToModel");
    this.fireTableDataChanged();
  }

  public String getColumnName(int col)
  {
    return column_headings[col];
  }

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

  public int getRowCount()
  {
    if ( rows != null )
    {
      return rows.length;
    }

    return 0;
  }

  public Object getValueAt(int row_num, int col)
  {
    cat.fine("SetComponentModel::getValueAt");
    Object result = null;

    if ( rows != null )
    {
      Object row = rows[row_num];
      if ( row != null )
      {
        // Now access the value indicated by that cols access path.
        try
        {
          result = PropertyUtils.getProperty(row, column_attr_paths[col]);
        }
        catch ( java.lang.IllegalAccessException iae )
        {
            cat.log(Level.SEVERE,"Error",iae);
          //iae.printStackTrace();
        }
        catch ( java.lang.reflect.InvocationTargetException ite )
        {
            cat.log(Level.SEVERE,"Error",ite);
          //ite.printStackTrace();
        }
        catch ( java.lang.NoSuchMethodException nsme )
        {
            cat.log(Level.SEVERE,"Error",nsme);
          //nsme.printStackTrace();
        }
        catch ( java.lang.IllegalArgumentException iae )
        { 
          // mostly happens when an intermediate collection is null.
            cat.log(Level.SEVERE,"Error",iae);
        }
      }
    }
    cat.fine("Set component model getValueAt - returning "+result);
   
    return result;
  }

  public Set getSet()
  {
    return data;
  }

  public boolean isEditable()
  {
    return editable;
  }

  public Object getRecord()
  {
    return record;
  }

  public String getReciprocalPropertyName()
  {
    return reciprocal_property_name;
  }

  public Object getRow(int index)
  {
    return rows[index];
  }

  public void setController(AdminControllerComponent c)
  {
    this.controller = (AbstractRecordController)c;
  }
  
  public void showAllRows()
  {     
      for(int i=0;i<getRowCount();i++)
      {
          notifyDoubleClickRow(i);
      }
  }

  public void notifyDoubleClickRow(int row)
  {
    cat.fine("SetComponentModel::notifyDoubleClickRow("+row+")");
    Object selected_object = getRow(row);

    String class_name = selected_object.getClass().getName();
    cat.fine("Class name is "+class_name);
    String required_layout = controller.getConfig().lookupDefaultView(class_name);
  
    EditRecordController rpc = new EditRecordController(controller.getConfig(),
                                                        controller.getSession(),
                                                        null,
                                                        false,
                                                        false,
                                                        controller,
                                                        controller.getRootController(),
                                                        false);

    rpc.selectTemplate(required_layout);
    
    String qualifier="";
    if(tab_heading_row !=-1)
    {
        Object value = getValueAt(row,tab_heading_row);
        if(value instanceof Date)
            qualifier = df.format(value);
        else
            qualifier = value.toString();
        qualifier=" ("+qualifier+")";
    }
    if(rpc.name==null)
        rpc.name="Editing.."+qualifier;
    else
        rpc.name=rpc.name +qualifier;
           
    controller.getRootController().addComponent(rpc);
    rpc.recordChanged(selected_object, true);
  }

  public void newRow(String class_name_of_new_object)
  {
    try
    {
      cat.fine("new row of class "+class_name_of_new_object);
      Class new_object_class = Class.forName(class_name_of_new_object);
      Object new_object = new_object_class.newInstance();
      // Adding the new instance to the set member..
      getSet().add(new_object);
      recordSetChanged();

      // if the new object has a setter that points back to the parent item,
      // set the value appropriately.
      String reciprocal_property_name = getReciprocalPropertyName();

      if ( ( reciprocal_property_name != null ) && ( ! reciprocal_property_name.equals("") ) )
      {
        cat.fine("set attr "+reciprocal_property_name+ " to new object");
        JXPathContext.newContext(new_object).setValue(reciprocal_property_name,controller.getSourceRecord());
      }

      if ( auto_edit_new_object )
      {
        // Use framework to auto-edit the new object
        cat.fine("Should auto edit new object");

        String required_layout = controller.getConfig().lookupDefaultView(class_name_of_new_object);
                                                                                                                                      
        EditRecordController rpc = null;
                                                                                                                                      
        rpc = new EditRecordController(controller.getConfig(),
                                       controller.getSession(),
                                       "Editing...",
                                       true,  // Needs save
                                       false, // Allow save new
                                       controller,
                                       controller.getRootController(),
                                       true);
                                                                                                                                      
        rpc.selectTemplate(required_layout);
        controller.getRootController().addComponent(rpc);
        rpc.recordChanged(new_object, true);
      }
    }
    catch ( java.lang.ClassNotFoundException cnfe )
    {
        cat.log(Level.SEVERE,"Error",cnfe);
      //cnfe.printStackTrace();
    }
    catch ( java.lang.InstantiationException ie )
    {
        cat.log(Level.SEVERE,"Error",ie);
      //ie.printStackTrace();
    }
    catch ( java.lang.IllegalAccessException iae )
    {
        cat.log(Level.SEVERE,"Error",iae);
     // iae.printStackTrace();
    }
  }

  
  public void addEditableChangeListener(com.k_int.AdminApp.widgets.ManyToManySetTable control)
  {
    //this.control = control; removed - rob
  }
}
