package com.afi.estimator.common
{
    import flash.utils.getDefinitionByName;
    import flash.xml.XMLDocument;
    import flash.xml.XMLNode;
    
    import mx.collections.ArrayCollection;
    import mx.rpc.xml.SimpleXMLEncoder;
    
    public class XMLConverter
    {
        public function XMLConverter()
        {
        }
        
        private var voArrayObj:Array=VOMapper.getVOMapper();
        //converts vo to request xml obj
        /*public function voToXml(vo:Object, qName:String):XML
        {
            
            var xmlDocument:XMLDocument=new XMLDocument();
            //var xmlSimpleEncoder:SimpleXMLEncoder=new SimpleXMLEncoder(xmlDocument);
            var xmlSimpleEncoder:XMLEncoder=new XMLEncoder(xmlDocument);
            //'qName' is the root tag name in XML object
            var xmlNode:XMLNode=xmlSimpleEncoder.encodeValue(vo,new QName(qName),xmlDocument);
            var xml:XML=new XML(xmlDocument.toString());
            var xml2:String = xml.toString().replace("<"+qName+">","");
            var xmlObj:String=FlexConstants.PROLOG+"<"+qName+ " "+FlexConstants.XML_NAMESPACE+">"+xml2;
            var xmlOrg:XML=new XML(xmlObj.toString());
            return xmlOrg;
        }*/
        
        public function xmlToVo(xml:XML):Object{
            // it gets all child nodes 
            var childXMLList:XMLList=xml.children();
            //'localName' is the  tagName of xml obj
            var localName:Object=xml.localName();
            //'parentClassName' is the parent root tag name 
            var parentClassName:String=FlexConstants.VO_PKGNAME+xml.localName();   
            //parent root tag will envoked
            var parentClassInst:Object=new (getDefinitionByName(parentClassName)as Class);
            //if there are any child nodes in original xml obj
            if(childXMLList!=null && childXMLList.length()>0){
                var arrylist:ArrayCollection=new ArrayCollection;
                // looping over the child nodes 
                for(var i:int=0;i<childXMLList.length();i++){
                    //  child node
                    var xml:XML=childXMLList[i] as XML;
                    
                    if(!hasChildProperty(xml)){
                        //child node tag name
                        var origName:String=xml.localName();
                        var tagName:String=this.getLowerCase(xml.localName());
                        var childLocalName:String=tagName;
                        //  'listProperty' contains just property name  follwoed by 'List' notation ,this logic figurs that property
                        //is type of single obj or arrayColletion
                        var listProperty:String=tagName+FlexConstants.LIST;
                        var localClassName:String=FlexConstants.VO_PKGNAME+this.getClassForAlias(childLocalName);
                        //'localClassInst' is child vo instance
                        var clazz:Class=getDefinitionByName(localClassName)as Class;
                        var localClassInst:Object=new (getDefinitionByName(localClassName)as Class);
                        this.getVOFromXML(childXMLList[i],localClassInst);
                        // if  'parentClassInst'  has  propetry type of single obj
                        if(parentClassInst.hasOwnProperty(tagName)){
                            parentClassInst[tagName]=localClassInst;
                            // if 'parentClassInst' has propety type of arraycollection
                        }else if(parentClassInst.hasOwnProperty(origName)){
                            parentClassInst[origName]=localClassInst;
                        }
                        else if(parentClassInst.hasOwnProperty(listProperty)){
                            
                            if(arrylist.length>0){
                                arrylist=this.checkList(arrylist,localClassInst,clazz);
                            }//if 'localArray' has length zero, then 'classInst' will added into 'localArray' directly
                            else{
                                
                                arrylist.addItem(localClassInst);
                            }
                            
                            
                            parentClassInst[listProperty]=arrylist;
                        }
                    }else{
                        // if node does not have any child nodes, we take here direct prop name and its value.
                        var propName:String=xml.localName();
                        var st:String=xml.valueOf();
                        // adding 'st' value to 'propName' propery in 'instance' obj
                        parentClassInst[propName]=st;
                    }
                    
                }
                
            }
            return parentClassInst;
        }
        // it loops over it selef as  many no of times as xml has child nodes, it retuns every child  of  root node 
        private function getVOFromXML(xml:XML,instance:Object):void{
            
            var childXMLList:XMLList=xml.children();
            var localArray:ArrayCollection=new ArrayCollection();
            var tempPropName:String='';
            var localStringArray:ArrayCollection=new ArrayCollection();
            for(var i:int=0; i<childXMLList.length();i++){
                var xml:XML=childXMLList[i];
                var xmlList:XMLList=xml.children();
                node: for(var j:int=0 ;j<xmlList.length();j++){
                    var xmlTemp:XML=xmlList[j] as XML;
                    var xmlListTemp:XMLList=xmlTemp.children();
                    //figures out still child node has child nodes
                    if(xmlListTemp.length()>0){
                        var tabName:String=this.getLowerCase(xml.localName());
                        var childLocalName:String=tabName;
                        var childLocalListName:String=childLocalName+FlexConstants.LIST;
                        // return orignal object name by chicking with alias names , which we mentioned in 'voMapper' obj in api package
                        var localClassName:String=FlexConstants.VO_PKGNAME+ this.getClassForAlias(childLocalName);
                        var clazz:Class=getDefinitionByName(localClassName)as Class;
                        var classInst:Object=new (getDefinitionByName(localClassName)as Class);
                        //if 'instance' has propety type of single obj
                        if(instance.hasOwnProperty(tabName)){
                            instance[tabName]=classInst;
                            
                        }//if 'instance' has property type arraycollection
                        else if(instance.hasOwnProperty(childLocalListName)){
                            /*if 'localArray' has one or more objects ,
                            *it compares 'classInst' with 'arry ' to make sure 'arry' has type of 'classInst' .if 'arry' already has
                            *same type of 'classInst' , 'classInst' will  added into 'arry' ,if 'arry ' does not have type of 'classInst' 
                            * arry gets new insatnce and 'classInst' willl added into new 'arry'.
                            */
                            if(localArray.length>0){
                                localArray=this.checkList(localArray,classInst,clazz);
                            }//if 'localArray' has length zero, then 'classInst' will added into 'localArray' directly
                            else{
                                
                                localArray.addItem(classInst);
                            }
                            // adding 'localArray' to arrayColletion property in 'instance' abj.
                            instance[childLocalListName]=localArray;
                        }
                        this.getVOFromXML(xml,classInst);
                        break node;
                    }else{
                        // if node does not have any child nodes, we take here direct prop name and its value.
                        var propName:String=xml.localName();
                        var st:String=xml.valueOf();
                        var listPropName:String=propName+FlexConstants.LIST;
                        if(instance.hasOwnProperty(listPropName)){
                            if(tempPropName!='' && tempPropName==propName){
                                localStringArray.addItem(st);
                            }else{
                                localStringArray=new ArrayCollection();
                                localStringArray.addItem(st);
                            }
                            tempPropName=propName;
                            instance[listPropName]=localStringArray;
                            
                        }else if(instance.hasOwnProperty(propName)){
                            // adding 'st' value to 'propName' propery in 'instance' obj
                            if(instance[propName] is Boolean){
                                instance[propName]=st=='true'?true:false;
                            }else{
                                instance[propName]=st;
                            }
                            
                        }
                        
                    }
                }
            }
            
        }
        
        /*
        * Returns the arrayObj ,in case of  same node type , arrayObj will keep add same object .If it finds new node type ,
        arrayObj gets new arry object 
        */
        private function checkList(arryObj:ArrayCollection,classInst:Object,clazz:Class):ArrayCollection{
            for(var i:int=0; i<arryObj.length;i++){
                if(arryObj[i] is clazz  ){
                    arryObj.addItem(classInst);
                    return arryObj;
                }
            }
            arryObj=new ArrayCollection();
            arryObj.addItem(classInst);
            return arryObj;
        }
        
        
        
        /*
        * Returns the fully qualified class name for
        * the childLocalName that is passed in. If no class is found, it returns original childLocalName
        */
        private function getClassForAlias( childLocalName:String ):String {
            
            var upperCaseChildName:String=this.getUpperCase(childLocalName);
            var lowerCaseChildName:String=this.getLowerCase(childLocalName);
            loop:for(var a:int=0; a<voArrayObj.length;a++){
                var mapObj:Object=voArrayObj[a]as Object;
                if(mapObj[FlexConstants.NAME]==(lowerCaseChildName) ||mapObj[FlexConstants.NAME]==(upperCaseChildName)  ){
                    childLocalName=mapObj[FlexConstants.VALUE] as String;
                    break loop;
                }
            }
            return childLocalName;
        }
        
        
        private function getLowerCase(childLocalName:String):String{
            
            var lowerCaseSt:String='';
            if(childLocalName!=null && childLocalName!=''){
                lowerCaseSt=childLocalName.toLocaleLowerCase().charAt(0)+
                    childLocalName.substr(1,childLocalName.length);
            }
            
            return lowerCaseSt;
            
        }
        
        private function getUpperCase(childLocalName:String):String{
            
            var upperCaseSt:String='';
            if(childLocalName!=null && childLocalName!=''){
                upperCaseSt=childLocalName.toUpperCase().charAt(0)+
                    childLocalName.substr(1,childLocalName.length);
            }
            
            return upperCaseSt;
        }
        //it figures out , are there any child nodes exist. If it does,it will return false  else, it will return true.
        private function hasChildProperty(xml:XML):Boolean{
            
            var xmlList:XMLList=xml.children();
            for(var j:int=0 ;j<xmlList.length();j++){
                var xmlTemp:XML=xmlList[j] as XML;
                var xmlListTemp:XMLList=xmlTemp.children();
                //figures out still child node has child nodes
                if(xmlListTemp.length()>0){
                    return false;
                }
                
            }
            return true;
        }
        
        
    }
}