/*
 *  List head and tail services class
 *
 *  2004 - 2011 Frantisek Zboril jr.
 *  Faculty of Information Technology
 *  zborilf@fit.vutbr.cz
 *  http://www.fit.vutbr.cz/~zborilf
 *
 * (C) Brno University of Technology
 * Freeware licence VUT v Brně
 * https://wis.fit.vutbr.cz/FIT/db/dir.php/dr/VZ2007/externiInformace/softwareNaWebu/Priloha2_rozh23.pdf

 */

package jTMass.core.jTMassPlatform.jTServices;

import jTMass.TMass;
import jTMass.core.jALLL.jTObjects.TAtom;
import jTMass.core.jALLL.jTObjects.TFail;
import jTMass.core.jALLL.jTObjects.TList;
import jTMass.core.jALLL.jTObjects.TObject;
import jTMass.core.jTMassPlatform.TPlatform;

public class TSListOperations extends TASSynchronousService{

    /*
     * h - head; param: list
     * t - tail; param: list
     * a - append; params: list list
     * c - construct; params object*
     * l - length of a list
     */

    private static final int _Max_Operations=5;

    TObject head(TObject param){
        if(!(param instanceof TList))
           return(new TFail());
        if(((TList)param).isEmpty())
            return(new TFail());
        return(((TList)param).get(0));
    }

    TObject tail(TObject param){
       if(!(param instanceof TList))
           return(new TFail());
       if(((TList)param).size()<2)
            return(new TFail());
       TList result=(TList)param.cloneObject();
       result.removeFirst();
       return(result);
    }

    TObject headTail(TObject operation, TObject list){
        if((operation instanceof TAtom)&&(list instanceof TList)){
            TObject newObject=(TList)list;
            TObject opResult;
            String opsS=operation.getContent();

            char[] ops=new char[_Max_Operations];

            if(opsS.length()>_Max_Operations){
                TMass._Terminal.reportError("Too many list operators (max "+_Max_Operations+")");
                return(new TFail());
            }

            opsS.getChars(0, opsS.length(), ops, 0);
            for(int i=0;i<opsS.length();i++)
                switch (ops[i]){
                    case 'h': opResult=head(newObject);
                        if(!(opResult instanceof TFail))
                            newObject=opResult;
                        else
                            return(new TFail());
                        break;

                    case 't': opResult=tail(newObject);
                        if(opResult instanceof TList)
                            newObject=(TList)opResult;
                        else
                            return(new TFail());
                        break;

                    default: return(new TFail());
                }

                return(newObject);
        }
        return(new TFail());
    }

    TObject append(TList parameters){
        TList resList=new TList();
        TObject item;
        for(int i=1;i<parameters.size();i++){
            item=parameters.get(i);
            if(!(item instanceof TList)){
                return(new TFail());
            }
            for(int j=0;j<((TList)item).size();j++)
                resList.append(((TList)item).get(j));
        }
        return(resList);
    }

    TObject construct(TList parameters, int index){
        TList resList=new TList();
        TObject item;
        for(int i=1;i<parameters.size();i++)
            resList.append(parameters.get(i));
        return(resList);
    }

    public TObject processOneService(TList parameters, int index){
        if(parameters.get(0) instanceof TAtom)
            try{
                String op=parameters.get(0).getContent();
                if((op.contains("h"))||(op.contains("t")))
                    return(headTail(parameters.get(0), parameters.get(index)));

                if(op.contentEquals("a"))
                    return(append(parameters));

                if(op.contentEquals("c")){
                    TObject params=parameters.get(index);
                    if(params instanceof TList)
                        if(((TList)params).size()==2){
                            TObject p1=((TList)params).get(0);
                            TObject p2=((TList)params).get(1);
                            if(p2 instanceof TList){
                                ((TList)p2).addFirst(p1);
                                return(p2);
                            }
                        }
                    return(new TFail());
                }

                if(op.contentEquals("l")){
                    Integer length=((TList)parameters.get(index)).size();
                    return(new TAtom(length.toString()));
                }

                if(op.contentEquals("avg")){

                    if(parameters.get(index) instanceof TList){
                        try{
                            TList sequence=(TList)parameters.get(index);
                            int size=sequence.size();
                            Integer res=new Integer(0);
                            for(int i=0;i<size;i++){
                                Integer item=Integer.valueOf(sequence.get(i).getContent());
                                res=res+item;
                            }
                            res=res/size;
                            return(new TAtom(res));
                        }catch(Exception e){
                            TMass._Terminal.reportError("Wrong number, list average value");
                            return(new TFail());
                        }
                    }
                    return(parameters.get(index));
                }
                
            }catch(Exception e){
                TMass._Terminal.reportError("Wrong parameters for list operation");
            }
        return(new TFail());
     }

    @Override
    public TObject processService(TList parameters, String clientName, String serviceName){
        super.processService(parameters,clientName,serviceName);
        if(parameters.size()<2)
            return(new TFail());
        if(parameters.size()==2)
            return(processOneService(parameters,1));
        else{
            TList result=new TList();
            for(int i=1;i<parameters.size();i++){
                TObject res=processOneService(parameters,i);
                if(res instanceof TFail)
                    return(res);
                result.add(res);
            }
            return(result);
        }
    }

    public TSListOperations(TPlatform platform){
        super(platform);
    }

}