package	hussam.math.operations.parser;

import hussam.math.operations.*;
import hussam.math.operations.dataBase.*;
import hussam.math.operations.extra.*;
import hussam.math.operations.factory.*;
import hussam.math.operations.parser.exceptions.*;
import java.util.*;
import java.util.regex.*;

public class HaniExpressionReader extends ExpressionReader{
	Iterator <String> scanner;
	String current;
	List<OperatorFactory<Operand>>sortedFactory;
	OperationsParser parser=new MyParser();
	public HaniExpressionReader(){
		sortedFactory=new Vector<OperatorFactory<Operand>>(OperatorFactoryDB.getInstance().getOperandFactories().values());
		Collections.sort(sortedFactory);
	}
	public OperationGroup readOperation(String stringOperation){
		List<String>strings=readSubStrings(stringOperation, getSubStringPositions(stringOperation));
//		Collections.reverse(strings);
		scanner=strings.iterator();
		current=scanner.next();
		OperationGroup o1=parseGroup();
//		o1=o1.optimize();
		return o1;
	}	
	public OperatorSource getOperatorSource(){return null;}
	OperationGroup parseGroup(){
		MyGroup g=new MyGroup();
		do{
			if(parser.isCloseParenthesis(current))break;
			Operation o1=parseOperands();
			if(o1!=null)
				g.addOperation(o1);
		}while(scanner.hasNext());
		return g;
	}
	Operation parseOperands(){
		return parseOperand(sortedFactory, 1);
	}
	private int getNextPowerLevel(List<OperatorFactory<Operand>>ops,int position){
		int power=ops.get(position).getType();
		while((position<ops.size())&&(power==ops.get(position).getType()))position++;
		return position;
	}
	Operation parseOperand(List<OperatorFactory<Operand>>ops,int position){
		Operation left=null;
		int power=ops.get(ops.size()-1).getType();
		if(position<ops.size()){
			power=ops.get(position).getType();
			System.out.println (ops.get(position).getName());
			left=parseOperand(ops, getNextPowerLevel(ops,position));
		}else return readTerm();
		if(parser.isOperand(current)){//.equals(ops.get(position).getName())){
			Operand o1=OperatorFactoryDB.getInstance().getOperandFactory(current).
					getNewOperator();
			if(scanner.hasNext())current=scanner.next();
			o1.set(left,parseOperand(ops,getNextPowerLevel(ops,position)));
			return o1;
		}
		return left;
	}
	Operation getVarOrFunction(){
		String name=current;
		current=scanner.next();
		if(parser.isOpenParenthesis(current)){
			Function f=OperatorFactoryDB.getInstance().getFunctionFactory(name).getNewOperator();
			f.setOperationGroup((OperationGroup)readTerm());
			return f;
		}else{
			Variable v=OperatorFactoryDB.getInstance().getGlobalVariable(name);
			return v;
		}
	}
	Operation readTerm(){
		Operation term=null;
		if(parser.isOpenParenthesis(current)){
			if(scanner.hasNext())current=scanner.next();
			term= parseGroup();
		}else if(parser.isOperand(current)){
			System.out.println (current);
			Operand o=OperatorFactoryDB.getInstance().getOperandFactory(current).getNewOperator();
			if(scanner.hasNext())current=scanner.next();
			o.setNext(readTerm());
			return o;
		}
		else if(parser.isVariable(current)){
			term=getVarOrFunction();
			return term;
		}
		else if(parser.isNumber(current)){
			term= new ConstantNumber(Double.parseDouble(current));
		}
		if(scanner.hasNext())current=scanner.next();
		return term;
	}
	private	static List<String>	readSubStrings(
			String operation, List<Integer>subs){
		Vector<String>strings=new Vector<String>();
		for(int	i=0;i<subs.size()-1;i++){
			strings.add(operation.substring(subs.get(i), subs.get(i+1)).trim());
		}
		return strings;
	}
	private	List<Integer>getSubStringPositions(String operation){
		Vector<Integer>parts=new Vector<Integer>();
		char NULL='\u0000';
		char previous=NULL;
		for(int	i=0;i<operation.length();i++){
			char current=operation.charAt(i);
			if(current==' ')continue;
			if(parser.isNumber(current)){
				if(parser.isOperand(previous)||parser.isComma(previous)||
						parser.isOpenParenthesis(previous)||parser.isCloseParenthesis(previous)||
						previous==NULL)
					parts.add(i);
			}else
				if(parser.isOperand(current)||parser.isComma(current)||
					parser.isOpenParenthesis(current)||parser.isCloseParenthesis(current)||
					previous==NULL){
					if((previous=='<' && current ==	'=') ||
							(previous=='<' && current =='>') ||
							(previous=='>' && current =='=')||
							(previous=='=' && current=='='));
					else{
						parts.add(i);
					}
				}else{
				if(parser.isOperand(previous)||parser.isComma(previous)||
						parser.isOpenParenthesis(previous)||parser.isCloseParenthesis(current)||
						previous==NULL)
					parts.add(i);
				}
			previous=current;
		}
		parts.add(operation.length());
		return parts;
	}

	public static void main(String[]args)throws Exception{
	//	String exp="+5*+4";
		String exp="12/4*3";
		System.out.println (exp);
		HaniExpressionReader reader=new HaniExpressionReader();
		Operation o1= reader.readOperation(exp);
		System.out.println (o1);
		System.out.println (o1.result());
	}
}
//*/

