import Query from '../../queries/Query.js'
import GraphObjectManager from './GraphObjectManager.js'
import { format } from '../../lib/libaux.js'

export default class LabelSegmentManager extends GraphObjectManager{
    constructor(...args){
        super(...args)
        this.observerIds=new Map();
    }

    async load(valueSet){

        var self=this;
        var vSet=Object.assign({},valueSet); //make copy of valueSet
        var labelSegmentQuery=async function(queryDefinition){

            let isConditional=queryDefinition.get('isConditional')
            let condition=queryDefinition.get('condition')
            let conditionQry=new Query(self.ecoreSync,queryDefinition.get("alias"),condition,queryDefinition.get("queryTarget"),queryDefinition.get("queryTargetAlias"));
            let defaultValue=queryDefinition.get('defaultValue')
            let resultFormat=queryDefinition.get('queryResultFormat') ? queryDefinition.get('queryResultFormat') : 's'
            let prefix=queryDefinition.get('prefix')
            if(prefix==null) prefix=''
            let suffix=queryDefinition.get('suffix')
            if(suffix==null) suffix=''

            let cmd=new eoq2.Cmp()

            let res=defaultValue;
            if(res==null) res=''
         
            let qryStr=queryDefinition.get('queryStr')

            if(isConditional)
            {           
                cmd.Get(conditionQry.build(vSet))     
                qryStr="@(IF,("+condition+"),("+qryStr+"),())"                 
            }
          
            let qry=new Query(self.ecoreSync,queryDefinition.get("alias"),qryStr,queryDefinition.get("queryTarget"),queryDefinition.get("queryTargetAlias"));
            cmd.Get(qry.build(vSet))         
          
            try{
                let queryRes=await self.ecoreSync.exec(cmd)
                if(isConditional)
                {
                    if(queryRes[0]) res=prefix+format(queryRes[1],resultFormat)+suffix;
                                             
                }
                else
                {
                    if(queryRes[0] != null ) res=prefix+format(queryRes[0],resultFormat)+suffix;                    
                }       
            }
            catch(e)
            {
                console.warn('default value used due to query failure')
                console.warn(cmd);
            }
            
            return res
        }

        var segmentQueries=this.type.model.get("queries").array().map(function(queryDefinition){            
            let QueryObj=new Query(self.ecoreSync,queryDefinition.get("alias"),queryDefinition.get("queryStr"),queryDefinition.get("queryTarget"),queryDefinition.get("queryTargetAlias"))          
            return {query:QueryObj,queryResults:labelSegmentQuery(queryDefinition)}
        })



        //wait until all segments have finished loading
        await Promise.all(segmentQueries.map(function(e){ return e.queryResults}))
        
        //update valueSet
        for(let i in segmentQueries)
        {              
            if(segmentQueries[i].query.hasAlias())
            {
                vSet[segmentQueries[i].query.getAlias()]=await segmentQueries[i].queryResults
            }    
        }
        
     

        var labelSegment=self.graphModelFactory.createLabelSegment(this.type);
        labelSegment.updateValueSet(vSet,true);

        return labelSegment;
    }

    async observe(valueSet,labelSegment){
        var self=this;
        var labelObservers=[];
        if(labelSegment.type != this.type ){ 
            throw 'cannot observe label segment of different type'
        }

        this.type.model.get("queries").array().forEach(function(queryDefinition){      

            let conditionQryStr=queryDefinition.get("condition") 
            let qryStr=queryDefinition.get("queryStr")    
            let obsvQryStr=new eoq2.Qry('')    
            if(queryDefinition.get('isConditional'))
            {
                obsvQryStr="@(IF,("+conditionQryStr+"),("+qryStr+"),%)"
            }
            else
            {
                obsvQryStr=qryStr;
            }                  
            let obsvQry=new Query(self.ecoreSync, queryDefinition.get("alias"),obsvQryStr,queryDefinition.get("queryTarget"),queryDefinition.get("queryTargetAlias"));     

            labelObservers.push(self.ecoreSync.observe(obsvQry.build(valueSet),async function(results,deltaPlus,deltaMinus){ 
                let res=queryDefinition.get('defaultValue')
                let prefix=queryDefinition.get('prefix')
                if(prefix==null) prefix=''
                let suffix=queryDefinition.get('suffix')
                if(suffix==null) suffix=''
                let resultFormat=queryDefinition.get('queryResultFormat') ? queryDefinition.get('queryResultFormat') : 's'

                //console.error('resultFormat in observer '+resultFormat)

                if(results!=null) res=prefix+format(results,resultFormat)+suffix
    
                //console.error('results in observer '+results)
                //console.error('label res')
                //console.error(res)

                let vSet={};
                if(queryDefinition.get('alias')!=null)
                {
                    vSet[queryDefinition.get('alias')]=res;
                    labelSegment.updateValueSet(vSet);
                }
            }));

        
        })

        Promise.all(labelObservers).then(function(obsvIds){
            self.observerIds.set(labelSegment,obsvIds);
        })
        return true
    }

    async unobserve(labelSegment)
    {        
        var self=this;
        if(this.observerIds.has(labelSegment)){
            let observerIds=this.observerIds.get(labelSegment);
            observerIds.forEach(function(obsvId){
                self.ecoreSync.unobserve(obsvId);
            })
        }
        return true      
    }

}