import GraphObject from './GraphObject.js'
import TypedObject from './TypedObject.js'
import ContainerProvider from './ContainerProvider.js'
import EObjectOwner from './EObjectOwner.js'
import RoutableObject from './RoutableObject.js'
import DeletableObject from './DeletableObject.js'
import EventProvider from './EventProvider.js'
import { multipleClasses }  from '../../lib/libaux.js'

export default class Edge extends multipleClasses(GraphObject,TypedObject,RoutableObject,DeletableObject,ContainerProvider,EObjectOwner){ 
    constructor(graphModel,type,parent=null){
        super();
        this.graphModel=graphModel;
        this.anchors=[];
    }

    init(){
        //Update support points
        var self=this
        this.on('ROUTED',function(supportPoints){       
            self.graphModel.layout.updateEdge(self,supportPoints);
        });
    }

    addAnchor(anchor){
        anchor.parent=this
        this.anchors.push(anchor);
        if(this.parent)
        {
            this.graphModel.events["EDGE_ANCHORS_CHANGED"].raise(this);
        }      
    }

    removeAnchor(anchor){
        let idx=this.anchors.indexOf(anchor);
        if(idx > -1)
        {
            this.anchors.splice(idx, 1);
        }      
        if(this.parent)
        {
            this.graphModel.events["EDGE_ANCHORS_CHANGED"].raise(this);
        } 
    }

    getAnchorByEObject(eObject)
    {
        return this.anchors.find(function(anchor){
            return anchor.getEObject()==eObject;
        })
    }

    getAnchorByEObjectId(objectId)
    {
        return this.anchors.find(function(anchor){
            return anchor.getEObjectId()==objectId;
        })
    }

    getSourceAnchors(){       
        return this.anchors.filter(function(e){ return e.getType()=="SOURCE"});
    }

    getTargetAnchors(){
        return this.anchors.filter(function(e){ return e.getType()=="TARGET"});
    }


    getSourceAnchor(){ 
        console.warn('Call to getSourceAnchor() is deprecated, use getSourceAnchors() instead')
        console.trace()
        let sourceAnchors=this.anchors.filter(function(e){ return e.getType()=="SOURCE"});
        if(sourceAnchors.length>1) console.warn('Ill-defined source anchors. There must only be one source anchor. First taken.')
        return sourceAnchors[0]
    }
    
    getTargetAnchor(){
        console.warn('Call to getTargetAnchor() is deprecated, use getTargetAnchors() instead')
        console.trace()
        let targetAnchors=this.anchors.filter(function(e){ return e.getType()=="TARGET"});
        if(targetAnchors.length>1) console.warn('Ill-defined target anchors. There must only be one target anchor. First taken.')
        return targetAnchors[0] 
    }

    getEdgeSpans(){

        let edgeSpans=[]
        
        let sources=this.getSourceAnchors()
        let targets=this.getTargetAnchors()   
        let edgeType=this.type.model.get("type")?this.type.model.get("type"):'ONE2ONE'

        let edgeSpan
        switch(edgeType)
        {
            case "ONE2ONE":
                edgeSpan={}
                edgeSpan.source=sources.length?sources[0]:null
                edgeSpan.target=targets.length?targets[0]:null
                if(edgeSpan.source && edgeSpan.target)
                {
                    edgeSpans.push(edgeSpan)
                }        
                break;
            case "ONE2MANY":
                let source=sources.length?sources[0]:null
                if(source)
                {
                    for(let target of targets)
                    {
                        if(target)
                        {
                            edgeSpan={}
                            edgeSpan.source=source
                            edgeSpan.target=target                    
                            edgeSpans.push(edgeSpan)                            
                        }
                    }
                }
                break;
            case "MANY2ONE":
                edgeSpan={}
                let target=targets.length?targets[0]:null
                if(target)
                {
                    for(let source of sources)
                    {
                        if(source)
                        {
                            edgeSpan={}    
                            edgeSpan.source=source  
                            edgeSpan.target=target                   
                            edgeSpans.push(edgeSpan)                            
                        }
                    }
                }
                break;
            case "MANY2MANY":                     
                for(let source of sources)
                {
                    if(source)
                    {
                        for(let target of targets)
                        {
                            if(target)
                            {
                                edgeSpan={}    
                                edgeSpan.source=source  
                                edgeSpan.target=target                   
                                edgeSpans.push(edgeSpan)   
                            }
                        }                         
                    }
                }
                break;
            default:
                edgeSpan={}
                //Default edge span (ONE2ONE)
                edgeSpan.source=sources.length?sources[0]:null
                edgeSpan.target=targets.length?targets[0]:null
                if(edgeSpan.source && edgeSpan.target)
                {
                    edgeSpans.push(edgeSpan)
                }   
                break;
        }       

      
        return edgeSpans
    }

    getStyle(source,target){
        var self=this;
        var style="";



        
        var setEdgeStrokeWidth=function(style)
        {
           style+="strokeWidth="+self.type.model.get("strokeWidth")+";" 
           return style;
        };

        var setEdgeColor=function(style)
        {
            if(self.type.model.get("autoColor"))
            {
                let color="FF0000"; //removed # because these are no longer supported in strings by EOQ
                let colorProvider=getColorProvider(self.type.model.get("colorNamespace"));
                if(!colorProvider)
                {
                    colorProvider=new ColorProvider(self.type.model.get("colorNamespace"),(a,b) => { return a==b; });
                }
                color=colorProvider.getColor(self.eObject);
                if(!color){color="FF000"}; //fallback
                style+="strokeColor=#"+color+";" //added # 
                
            }
            else
            {
                let color=self.type.model.get("color");
                if(!color){color="FF000"}; //fallback color (red)
                style+="strokeColor=#"+color+";" //added # 
            }
            return style;           
        }

        var setEdgeAnchorAttachment=function(style,anchor)
        {

            var keyword;
            if(anchor.getType()=="SOURCE")
            {
                keyword="exit";
            }

            if(anchor.getType()=="TARGET")
            {
                keyword="entry";
            }

            if(keyword)
            {
                var attach=anchor.type.model.get("attach");
                var offsetType=anchor.type.model.get("offsetType")?anchor.type.model.get("offsetType"):0;
                var offsetX=Number.parseFloat(anchor.type.model.get("offsetX")?anchor.type.model.get("offsetX"):0);
                var offsetY=Number.parseFloat(anchor.type.model.get("offsetY")?anchor.type.model.get("offsetY"):0);

                //Attachment position defaults
                let attachX=0
                let attachY=0

                switch(attach)
                {
                    case "NORTH":
                        attachX=0.5
                        attachY=0
                        break;
                    case "SOUTH":
                        attachX=0.5
                        attachY=1
                        break;
                    case "EAST":
                        attachX=1
                        attachY=0.5
                        break;
                    case "WEST":
                        attachX=0.0
                        attachY=0.5
                        break;
                    case "ANY":
                        attachX=0
                        attachY=0
                        break;
                    default:
                        attachX=0.5
                        attachY=1
                        break;
                }

              
                style+=keyword+"X="+attachX.toString()+";"+keyword+"Y="+attachY.toString()+";"+keyword+"Dx="+offsetX.toString()+";"+keyword+"Dy="+offsetY.toString()+";";
                if(offsetX!=0 || offsetY!=0) style+=keyword+"Perimeter=0;"
                
                if(attach=="NORTH" || attach=="SOUTH")
                {
                    style+="edgeStyle=elbowEdgeStyle;elbow=vertical;"
                }

                if(attach=="EAST" || attach=="WEST")
                {
                    style+="edgeStyle=elbowEdgeStyle;elbow=horizontal;"
                }

            }
            return style
        };

        var setCurved=function(style){
            if(self.type.model.get("curved")){
                style+="curved=1;"
            }
            else
            {
                style+="curved=0;"
            }
            return style
        }

        style=setEdgeStrokeWidth(style);
        style=setEdgeColor(style);
        style=setEdgeAnchorAttachment(style,source);
        style=setEdgeAnchorAttachment(style,target);
        style=setCurved(style)

        return style;

    }

    addContainer(container)
    {
        super.addContainer(container);
        this.graphModel.addToIndex(container)
    }

    removeContainer(container)
    {
        super.removeContainer(container);
        this.graphModel.removeFromIndex(container)
    }
    
    delete(source,target){
        let valueSet={}
        valueSet["SOURCE"]=source.eObject
        valueSet["TARGET"]=target.eObject
        super.delete(valueSet)
    }


    toString()
    {
        return '';
    }

}