/*
 * Created on Feb 7, 2004
 *
 */
package LumiSoft.Data;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;

import javax.swing.event.EventListenerList;

/**
 * 
 */
public class DataView implements Iterable<DataRowView>
{
	private EventListenerList      m_pListners         = null;
	private DataTable              m_pTable            = null;
	private ArrayList<DataRowView> m_pViewRows         = null;
	private ArrayList<DataRowView> m_pViewFilteredRows = null;
	private DataRowView            m_pParentRow        = null;
	private String                 m_RowFilter         = "";
	private String                 m_Sort              = "";
	
	/**
	 * 
	 * @param table
	 */
	public DataView(DataTable table)
	{
		this(table,"",null);
	}
	
	protected DataView(DataTable table,String relationName,DataRowView parentRow)
	{
		m_pTable     = table;
		m_pParentRow = parentRow;
		
		m_pViewFilteredRows = new ArrayList<DataRowView>();
		m_pListners = new EventListenerList();
		
		CreateView(relationName);
	}
	
	
	private void CreateView(String relationName)
	{
		m_pViewRows = new ArrayList<DataRowView>();
		
		if(relationName.length() > 0){
			DataRelation relation = m_pTable.getDataSet().getRelations().get(relationName);		
			DataTable childTable = relation.getChildColumns()[0].getTable();
			m_pTable = childTable;
			
			for(int i=0;i<m_pTable.getRows().getCount();i++){
				if(m_pParentRow.get(relation.getParentColumns()[0].getColumnName()).equals(childTable.getRows().get(i).get(relation.getChildColumns()[0]))){
					m_pViewRows.add(new DataRowView(this,childTable.getRows().get(i)));
				}
			}
		}
		else{
			for(int i=0;i<m_pTable.getRows().getCount();i++){
				m_pViewRows.add(new DataRowView(this,m_pTable.getRows().get(i)));
			}
		}
	}
	
	
	protected void Delete(DataRowView row)
	{
		m_pViewRows.remove(row);
	}
	
	/**
	 * Adds a new row to the DataView.
	 * @return
	 */
	public DataRowView AddNew()
	{
		DataRowView drV = new DataRowView(this,m_pTable.NewRow(),true);
		m_pViewRows.add(drV);
		
		return drV;
	}
	
	
	private void Sort(int startIndex,int endIndex,String columnName,boolean asc_desc)
	{
		// Sort (Bubble sorting)
		boolean swapped = true; 
		int i = endIndex;
		while(swapped && (i >= 1)){								
			swapped = false;
			for(int j=startIndex;j<=(i-1);j++){
				DataRowView dr        = m_pViewRows.get(j);
				DataRowView drNextRow = m_pViewRows.get(j + 1);
					
				Object drValue        = dr.get(columnName);
				Object drNextRowValue = drNextRow.get(columnName);
		//		if(drValue == null){
		//			drValue = new String("null");
		//		}
		//		if(drNextRowValue == null){
		//			drNextRowValue = new String("null");
		//		}
						
				if(asc_desc){
					
					if(CompareValues(asc_desc,drValue,drNextRowValue) > 0){
				//	if(((Comparable)drValue).compareTo(drNextRowValue) > 0){
						// Swap items
						m_pViewRows.set(j,drNextRow);
				    	m_pViewRows.set(j + 1,dr);
						swapped = true; 
					}
				}
				else{
					if(CompareValues(asc_desc,drValue,drNextRowValue) < 0){
				//	if(((Comparable)drValue).compareTo(drNextRowValue) < 0){
						// Swap items
						m_pViewRows.set(j,drNextRow);
				    	m_pViewRows.set(j + 1,dr);
						swapped = true; 
					}
				}					
			}
			i--;
		}		
	}
	
	private int CompareValues(boolean asc_desc,Object sourceValue,Object compareValue)
	{
		if(asc_desc){
			if(sourceValue == null && compareValue == null){
				return 0;
			}
			else if(sourceValue != null && compareValue == null){
				return 1;
			}
			else if(sourceValue == null){
				return 1;			
			}
			else{
				return ((Comparable)sourceValue).compareTo(compareValue);
			}
		}
		else{
			if(sourceValue == null && compareValue == null){
				return 0;
			}
			else if(sourceValue != null && compareValue == null){
				return -1;
			}
			else if(sourceValue == null){
				return -1;			
			}
			else{
				return ((Comparable)sourceValue).compareTo(compareValue);
			}
		}		
	}
	
	
	/**
	 * Gets the number of records in the DataView after RowFilter and RowStateFilter have been applied.
	 * @return
	 */
	public int getCount()
	{
		if(getRowFilter().length() > 0){
			return m_pViewFilteredRows.size();
		}
		else{
			return m_pViewRows.size();
		}
	}
	
	/**
	 * Gets a row of data from a specified table. 
	 * @param index
	 * @return
	 */
	public DataRowView get(int index)
	{
		if(getRowFilter().length() > 0){
			return m_pViewFilteredRows.get(index);
		}
		else{
			return m_pViewRows.get(index);
		}
	}
	
	/**
	 * Gets the expression used to filter which rows are viewed in the DataView.
	 * @return
	 */
	public String getRowFilter()
	{
		return m_RowFilter;
	}
	/**
	 * Sets the expression used to filter which rows are viewed in the DataView.
	 * @param value
	 */
	public void setRowFilter(String value)
	{			
		if(!m_RowFilter.equals(value)){
			m_RowFilter = value;
			
			m_pViewFilteredRows.clear();
			
			// TODO: support multiple filters			
			if(getRowFilter().indexOf("=") > -1){
				String[] p = getRowFilter().toLowerCase().split("=",2);
				String columnName   = p[0].trim();
				String compareValue = p[1].trim();
				if(compareValue.startsWith("'")){
					compareValue = compareValue.substring(1);
				}
				if(compareValue.endsWith("'")){
					compareValue = compareValue.substring(0,compareValue.length() - 1);
				}
				
				for(DataRowView dr : m_pViewRows){					
					if(dr.get(columnName) != null && dr.get(columnName).toString().toLowerCase().equals(compareValue.toLowerCase())){
						m_pViewFilteredRows.add(dr);
					}
				}
			}
			else if(getRowFilter().toLowerCase().indexOf("like") > -1){
				String[] p = getRowFilter().toLowerCase().split("like",2);
				String columnName   = p[0].trim();
				String compareValue = p[1].trim();
				if(compareValue.startsWith("'")){
					compareValue = compareValue.substring(1);
				}
				if(compareValue.endsWith("'")){
					compareValue = compareValue.substring(0,compareValue.length() - 1);
				}
				
				if(compareValue.startsWith("*") || compareValue.endsWith("*")){
					compareValue = compareValue.substring(1,compareValue.length() - 1);
						
					for(DataRowView dr : m_pViewRows){			
						if(dr.get(columnName) != null && dr.get(columnName).toString().toLowerCase().indexOf(compareValue) > -1){							
							m_pViewFilteredRows.add(dr);
						}
					}	
				}
				else{
					System.out.println("TODO:" + getRowFilter());
				}				
			}
			
			RaiseListChanged();
		}
	}
	
	/**
	 * Gets the sort column or columns, and sort order for the DataView.
	 * @return
	 */
	public String getSort()
	{
		return m_Sort;
	}
	/**
	 * Sets the sort column or columns, and sort order for the DataView.
	 * @param value
	 */
	public void setSort(String value)
	{
		// Clear sorting, restore default DataTable rows order.
		if(value == null || value.length() == 0){		
			ArrayList<DataRowView> rows = (ArrayList<DataRowView>)m_pViewRows.clone();
			m_pViewRows.clear();
			for(DataRow dr : m_pTable.getRows()){
				for(DataRowView drV : rows){
					if(drV.getRow().equals(dr)){
						rows.remove(drV);
						m_pViewRows.add(drV);
						break;
					}
				}
			}
		}
		else{			
			String lastColumn = "";
			String[] sortList = value.split(",");
			for(String sort : sortList){
				String[] sortParams = sort.split(" ");			
				String   columnName = "";
				boolean  asc_desc   = true;
				
				columnName = sortParams[0];
				// Column + [ASC | DESC] specified
				if(sortParams.length == 2){
					if(sortParams[1].toLowerCase().indexOf("asc") > -1){
						asc_desc = true;
					}
					else{
						asc_desc = false;
					}
				}
				
				// First sort
				if(lastColumn.length() == 0){
					Sort(0,m_pViewRows.size() - 1,columnName,asc_desc);
				}
				else{
					// Find last sort duplicate rows and sort them with specified sort
					
					int rowNumer = 1;
					int duplicateStart = -1;
					while(rowNumer < m_pViewRows.size()){
						Object valueLast    = m_pViewRows.get(rowNumer - 1).get(lastColumn);
						Object valueCurrent = m_pViewRows.get(rowNumer).get(lastColumn);
						
						if(valueLast == null){
							valueLast = "null";
						}
						if(valueCurrent == null){
							valueCurrent = "null";
						}
						
						// Current value equals to last value and we haven't started counting duplicates 
						if(valueLast.equals(valueCurrent)){
							if(duplicateStart == -1){
								duplicateStart = rowNumer - 1;
							}
						}
						// There are some duplicate values and they ended, sort them and start looking newones
						else if(duplicateStart != -1){
							Sort(duplicateStart,rowNumer - 1,columnName,asc_desc);
							duplicateStart = -1;
						}
						rowNumer++;
					}
					
					// Sort remaining duplicates
					if(duplicateStart != -1){
						Sort(duplicateStart,rowNumer - 1,columnName,asc_desc);
					}
				}
				
				lastColumn = columnName;
			}
			
		/*	ArrayList<String[]> sortList = new ArrayList<String[]>();
				
			String[] sortColumns = value.split(",");
			for(int i=0;i<sortColumns.length;i++){
				// Column + [ASC | DESC] specified
				if(sortColumns[i].indexOf(" ") > 0){
					String[] col_sortKey = sortColumns[i].split(" ");
					
					sortList.add(col_sortKey);
				}
				// Only column specified (use ASC as default)
				else{
					sortList.add(new String[]{sortColumns[i],"ASC"});
				}
			}
					
			// Sort (Bubble sorting)
			for(int s=0;s<sortList.size();s++){
				String[] col_sortKey = (String[])sortList.get(s);
				
				boolean asc_desc = false;
				if(col_sortKey[1].toLowerCase().equals("asc")){
					asc_desc = true;
				}
				
				Sort(0,m_pViewRows.size() - 1,col_sortKey[0],asc_desc);
			*/		
		/*		boolean swapped = true; 
				int i = m_pViewRows.size() - 1;
				while(swapped && (i >= 1)){								
					swapped = false;
					for(int j=0;j<=(i-1);j++){
						DataRowView dr        = m_pViewRows.get(j);
						DataRowView drNextRow = m_pViewRows.get(j + 1);
						
						Object drValue = dr.get(col_sortKey[0]);
						Object drNextRowValue = drNextRow.get(col_sortKey[0]);
						if(drValue == null){
							drValue = new String("null");
						}
						if(drNextRowValue == null){
							drNextRowValue = new String("null");
						}
							
						if(asc_desc){
							if(((Comparable)drValue).compareTo(drNextRowValue) > 0){
								// Swap items
								m_pViewRows.set(j,drNextRow);
						    	m_pViewRows.set(j + 1,dr);
								swapped = true; 
							}
						}
						else{
							if(((Comparable)drValue).compareTo(drNextRowValue) < 0){
								// Swap items
								m_pViewRows.set(j,drNextRow);
						    	m_pViewRows.set(j + 1,dr);
								swapped = true; 
							}
						}					
					}
					i--;
				}
			}*/
		}
		
		m_Sort = value;
	}
	
	/**
	 * Gets or sets the source DataTable.
	 * @return
	 */
	public DataTable getTable()
	{
		return m_pTable;
	}
	
	
	/**
	 * Gets iterator.
	 */
	public Iterator<DataRowView> iterator()
	{
		// Row filter is specified, need return only rows what match filtering criteria.
		if(getRowFilter().length() > 0){			
			return m_pViewFilteredRows.iterator();
		}
		else{		
			return m_pViewRows.iterator();
		}
	}
	
	
	/**
	 * Adds the specified action listener to receive action events
	 * from this button.
	 * @param l the action listener
	 */ 
	public void addListChangedListener(ActionListener l) 
	{
		m_pListners.add(ActionListener.class,l);
	}

	/**
	 * Removes the specified action listener so it no longer receives
	 * action events from this button.
	 * @param l the action listener
	 */ 
	public void removeListChangedListener(ActionListener l) 
	{
		m_pListners.remove(ActionListener.class,l);
	}
	
	/**
	 * Raises ListChanged event.
	 *
	 */
	protected void RaiseListChanged()
	{
		Object[] listeners = m_pListners.getListenerList();
		// loop through each listener and pass on the event if needed		
		for(int i=0;i < listeners.length;i++){
			if(listeners[i] == ActionListener.class){
				// pass the event to the listeners event dispatch method
				((ActionListener)listeners[i+1]).actionPerformed(new ActionEvent(this,1,""));
			}            
		}
	}
}
