import React, { useEffect, useLayoutEffect, useRef } from 'react'
import Attributes from 'react-native-painter/src/Components/Constants'


const clamp = (num) =>{
    return num < 0 ? 0 : (num > 1 ? 1 : num) 
}

//text-after-edge -> descender
//text-before-edge-> ascender
//hanging -> capheight
//central -> center
//middle -> middle
//none -> ""

const getBaselineWeb = (b)=>{
    var result = ""
    switch(b){
        case "descender":
            result = "text-after-edge"
            break
        case "ascender":
            result = "text-before-edge"
            break
        case "capHeight":
            result = "hanging"
            break
        case "center":
            result = "central"
            break
        case "middle":
            result = "middle"
            break
        default:
            result = ""
            break
    }

    return result
}

const TextWeb = React.forwardRef((props,ref)=>{

    const myRef = ref ? ref : useRef()
  

    const {

        x,
        y,
        text,
        font,
        fontSize,
        fontStyle,
        baseline,
        textAnchor,
        verticalOffset,
        horizontalOffset,
        
        isChildMask,
        painterKey,
        viewBox,
        align,
        aspect,

        fill,
        fillOpacity,

        stroke,
        strokeOpacity,
        strokeWidth,
                
        shadow,
        shadowRadius,
        shadowOffset,
        shadowOffsetX,
        shadowOffsetY,
        shadowPercentageValue,
        shadowRect,

        mask,

        opacity,
        translateZ,

        transX,
        transY,
        transPercentageValue,

        rot,
        rotO,
        rotOx,
        rotOy,
        rotPercentageValue,

        sc,
        scX,
        scY,
        scO,
        scOx,
        scOy,
        scPercentageValue,
    
       style,
        ...rest 
    } = props


    //MARK: Props

    const lx = x === undefined ? 0 : x
    const ly = y === undefined ? 0 : y
    const content = text === undefined ? "" : text
    const typeface = font === undefined ? "" : font
    const fontStyl = fontStyle === 'italic' ? "italic" : "normal"
    const fontWeg = fontStyle === "bold" ? "bold" : "normal"
    const fontSiz = fontSize === undefined ? 12 : fontSize
    const basel = baseline === undefined ? "" : getBaselineWeb(baseline)
    const textAn = textAnchor === undefined ? "" : textAnchor
 
    const isMasking = isChildMask === undefined ? false : isChildMask

    //MARK : Paintable


    const fc = fill === undefined ? '' : fill
    const fo = fillOpacity === undefined ? "" : `${fillOpacity}`
    
    const stc = stroke === undefined ? '' : stroke
    const so = strokeOpacity === undefined ? "" : `${strokeOpacity}`
    const sw = strokeWidth === undefined ? 1 : strokeWidth
   

    const shc = shadow === undefined ? 'rgba(0,0,0,0)'.split(",") : shadow.split(",")
    const shr = shadowRadius === undefined ? 2 : shadowRadius
    const shox = shadowOffset === undefined ? (shadowOffsetX === undefined ? 2 : shadowOffsetX ) : shadowOffset
    const shoy =  shadowOffset === undefined ? (shadowOffsetY === undefined ? 2 : shadowOffsetY) : shadowOffset
    const shRect = shadowRect === undefined ? {x:-2, y:-2 , w:5,h:5, units:'objectBoundingBox'} : shadowRect

    const mk = mask === undefined ? "" : mask
    const op = opacity === undefined ? "" : `${opacity}`
   
    const dx = transX === undefined ? 0 : transX
    const dy = transY === undefined ? 0 : transY

    const scaleX = sc === undefined ? ( scX === undefined ? 1 : scX) : sc
    const scaleY = sc === undefined ?  (scY === undefined ? 1 : scY) : sc
    const scaleOX = scO === undefined ? ( scOx === undefined ? 0 : scOx) : scO
    const scaleOY = scO === undefined ?  (scOy === undefined ? 0 : scOy) : scO

    const rotation = rot === undefined ? 0 : rot
    const rotationOX = rotO === undefined ? ( rotOx === undefined ? 0 : rotOx) : rotO
    const rotationOY = rotO === undefined ?  (rotOy === undefined ? 0 : rotOy) : rotO


    const transform = `rotate(${rotation} ${rotationOX} ${rotationOY}) translate(${scaleOX} ${scaleOY}) scale(${scaleX} ${scaleY}) translate(${-scaleOX} ${-scaleOY}) translate(${dx} ${dy})`
    const userKey = painterKey === undefined ? "" : painterKey

    const keyElemet = Attributes.elements.prefix
    const keyFilter = `${keyElemet}${Attributes.elements.filter}${userKey}`

    const filterShadowProp = `url(#${keyFilter})`

    const isFillTransparent = fc === `rgba(0, 0, 0, 0)` || fc === "transparent"



   
    return(
        <g  ref={myRef} opacity={op} mask={`url(#${mk})`}  transform={transform} 
        curtransform={`${rotation} ${rotationOX} ${rotationOY} ${scaleX} ${scaleY} ${scaleOX} ${scaleOY} ${dx} ${dy}`}
        >

    
        <svg style={{width:'100%',height:'100%',overflow:'visible'}} viewBox={viewBox} 
             preserveAspectRatio={`${align} ${aspect}`}>
        
      
            <defs>
                <filter id={keyFilter}
                    filterUnits={`${shRect.units}`}
                    x={`${shRect.x}`} y={`${shRect.y}`} width={`${shRect.w}`} height={`${shRect.h}`}>
                    <feDropShadow 
                      id={`${keyElemet}${Attributes.elements.shadow}${userKey}`}
                     dx={shox} dy={shoy} stdDeviation={shr} 
                     floodColor={shc} 
                     />
                </filter>

            </defs>
   

       
            <text id={`${keyElemet}${Attributes.elements.fill}${userKey}`}
             x={lx} y={ly} fontFamily={typeface} fontSize={fontSiz} fontStyle={fontStyl} fontWeight={fontWeg} textAnchor={textAn}
            dominantBaseline={basel}
           
           filter={!isFillTransparent   ? filterShadowProp : ""} 
           fill={fc} fillOpacity={fo}  
           stroke={"none"} 
           >
                        {content}
            </text>
           
                <g    id={`${keyElemet}${Attributes.elements.gShadow}${userKey}`} 
                filter={isFillTransparent ? filterShadowProp : ""}   >

                    <text  id={`${keyElemet}${Attributes.elements.stroke}${userKey}`}
                    x={lx} y={ly} fontFamily={typeface} fontSize={fontSiz} fontStyle={fontStyl} fontWeight={fontWeg} textAnchor={textAn}
                          dominantBaseline={basel}
                        fill={"none"}
                        stroke={stc} strokeOpacity={so}
                        strokeWidth={sw} 
                    >

                            {content}
                        </text>
              
                </g>
          
      
    </svg>
    </g>
    )
})

export default class Text extends React.PureComponent{

    
    constructor(props){
        super(props)
        this.keyElemet = Attributes.elements.prefix
        this.myRef = React.createRef()
        this.setNativeProps = this.setNativeProps.bind(this)
        this.updateProp = this.updateProp.bind(this)
        this.handleProps = this.handleProps.bind(this)
        this.handleCommonProps = this.handleCommonProps.bind(this)
        this.handleShadow = this.handleShadow.bind(this)
        this.updateAttribute = this.updateAttribute.bind(this)
        this.getAttribute = this.getAttribute.bind(this)
        this.getElement = this.getElement.bind(this)
      
    }


    setNativeProps(object){
        if(this.myRef.current && this.props.painterKey){
            let keys = Object.keys(object)
            for(var i = 0; i < keys.length;i++){
                let k = keys[i]
                let value = object[k]
                this.updateProp(k,value)
               
            }

            let isStyle = object.hasOwnProperty('style')
            if(isStyle){
                let keysStyle = Object.keys(object.style)
                for(var i = 0; i < keysStyle.length;i++){
                    let k = keysStyle[i]
                    let value = object.style[k]
                    this.updateProp(k,value)
                   
                }
            }
          
        }
    }

    updateProp(k,value){
        let isProp = this.handleProps(k,value)
        if(!isProp){
            this.handleCommonProps(k,value)
        }
    }


    handleProps(k,value){
        switch(k){
            case "text":
      
                let f = this.getElement(Attributes.elements.fill)
                let s = this.getElement(Attributes.elements.stroke)
                if(f) f.textContent = value
                if(s) s.textContent = value
                return true;
            case "x":
            case "y":
            case "font":
            case "fontSize":
            case "textAnchor":
                this.updateAttribute(Attributes[k],value,this.getElement(Attributes.elements.fill))
                this.updateAttribute(Attributes[k],value,this.getElement(Attributes.elements.stroke))
                return true;
            case "fontStyle":
                if(value === 'bold') {
                    this.updateAttribute(Attributes.fontWeight,value,this.getElement(Attributes.elements.fill)) 
                    this.updateAttribute(Attributes.fontStyle,'normal',this.getElement(Attributes.elements.fill))
                    this.updateAttribute(Attributes.fontWeight,value,this.getElement(Attributes.elements.stroke)) 
                    this.updateAttribute(Attributes.fontStyle,'normal',this.getElement(Attributes.elements.stroke))
                }else{
                    this.updateAttribute(Attributes.fontWeight,'normal',this.getElement(Attributes.elements.fill)) 
                    this.updateAttribute(Attributes.fontStyle,value,this.getElement(Attributes.elements.fill))
                    this.updateAttribute(Attributes.fontWeight,'normal',this.getElement(Attributes.elements.stroke)) 
                    this.updateAttribute(Attributes.fontStyle,value,this.getElement(Attributes.elements.stroke))
                }
                return true;
            case "baseline":
                this.updateAttribute(Attributes[k],getBaselineWeb(value),this.getElement(Attributes.elements.fill))
                this.updateAttribute(Attributes[k],getBaselineWeb(value),this.getElement(Attributes.elements.stroke))
                return true;
      
         }
         return false
    }

    handleCommonProps(k,value){
        
        if(k.includes('fill')){
            if(k === 'fill'){
                let keyFilter = `${this.keyElemet}${Attributes.elements.filter}${this.props.painterKey}`
                let filterShadowProp = `url(#${keyFilter})`
                let isFillTransparent =  value === `rgba(0, 0, 0, 0)` || value === "transparent"
                let elFill = this.getElement(Attributes.elements.fill)
                this.updateAttribute(Attributes[k],value,elFill)
                this.updateAttribute(Attributes.filter,!isFillTransparent ? filterShadowProp : "",elFill)
                this.updateAttribute(Attributes.filter,isFillTransparent ? filterShadowProp : "",this.getElement(Attributes.elements.gShadow))
            }else{
                this.updateAttribute(Attributes[k],value,this.getElement(Attributes.elements.fill))
            }
        }else if(k.includes('stroke')){
            this.updateAttribute( Attributes[k],value,this.getElement(Attributes.elements.stroke))
        }else if(k.includes('shadow')){
             this.handleShadow(k,value)
        }else if(k === 'opacity'){
            this.updateAttribute(Attributes.opacity,value,this.myRef.current)
        }else if(k === 'mask'){
            this.updateAttribute(Attributes.mask,`url(#${value})`,this.myRef.current)
        }//transform
        else{
            var container = this.myRef.current
            let t = this.getAttribute(Attributes.curTransform,container).split(' ')
            var valueT = ""
            var currT = ""
            switch(k){
                case "transX":
                        valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${t[5]} ${t[6]}) scale(${t[3]} ${t[4]}) translate(${-t[5]} ${-t[6]}) translate(${value} ${t[8]})`
                        currT = `${t[0]} ${t[1]} ${t[2]} ${t[3]} ${t[4]} ${t[5]} ${t[6]} ${value} ${t[8]}`
                   break;
                case "transY":
                        valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${t[5]} ${t[6]}) scale(${t[3]} ${t[4]}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${value})`
                        currT = `${t[0]} ${t[1]} ${t[2]} ${t[3]} ${t[4]} ${t[5]} ${t[6]} ${t[7]} ${value}`
                    break;
                case "rot":
                         valueT = `rotate(${value} ${t[1]} ${t[2]}) translate(${t[5]} ${t[6]}) scale(${t[3]} ${t[4]}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${t[8]})`
                         currT = `${value} ${t[1]} ${t[2]} ${t[3]} ${t[4]} ${t[5]} ${t[6]} ${t[7]} ${t[8]}`
                     break;
                case "rotO":
                         valueT = `rotate(${t[0]} ${value} ${value}) translate(${t[5]} ${t[6]}) scale(${t[3]} ${t[4]}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${t[8]})`
                         currT = `${t[0]} ${value} ${value} ${t[3]} ${t[4]} ${t[5]} ${t[6]} ${t[7]} ${t[8]}`
                     break;
                case "rotOx":
                         valueT = `rotate(${t[0]} ${value} ${t[2]}) translate(${t[5]} ${t[6]}) scale(${t[3]} ${t[4]}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${t[8]})`
                         currT = `${t[0]} ${value} ${t[2]} ${t[3]} ${t[4]} ${t[5]} ${t[6]} ${t[7]} ${t[8]}`
                    break;
                case "rotOy":
                         valueT = `rotate(${t[0]} ${t[1]} ${value}) translate(${t[5]} ${t[6]}) scale(${t[3]} ${t[4]}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${t[8]})`
                         currT = `${t[0]} ${t[1]} ${value} ${t[3]} ${t[4]} ${t[5]} ${t[6]} ${t[7]} ${t[8]}`
                     break;
                case "sc":
                         valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${t[5]} ${t[6]}) scale(${value} ${value}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${t[8]})`
                         currT = `${t[0]} ${t[1]} ${t[2]} ${value} ${value} ${t[5]} ${t[6]} ${t[7]} ${t[8]}`
                     break;
                case "scX":
                         valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${t[5]} ${t[6]}) scale(${value} ${t[4]}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${t[8]})`
                         currT = `${t[0]} ${t[1]} ${t[2]} ${value} ${t[4]} ${t[5]} ${t[6]} ${t[7]} ${t[8]}`
                     break;
                case "scY":
                         valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${t[5]} ${t[6]}) scale(${t[3]} ${value}) translate(${-t[5]} ${-t[6]}) translate(${t[7]} ${t[8]})`
                         currT = `${t[0]} ${t[1]} ${t[2]} ${t[3]} ${value} ${t[5]} ${t[6]} ${t[7]} ${t[8]}`
                    break;
                case "scO":
                         valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${value} ${value}) scale(${t[3]} ${t[4]}) translate(${-value} ${-value}) translate(${t[7]} ${t[8]})`
                         currT = `${t[0]} ${t[1]} ${t[2]} ${t[3]} ${t[4]} ${value} ${value} ${t[7]} ${t[8]}`
                    break;
                case "scOx":
                         valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${value} ${t[6]}) scale(${t[3]} ${t[4]}) translate(${-value} ${-t[6]}) translate(${t[7]} ${t[8]})`
                         currT = `${t[0]} ${t[1]} ${t[2]} ${t[3]} ${t[4]} ${value} ${t[6]} ${t[7]} ${t[8]}`
                    break;
                case "scOy":
                         valueT = `rotate(${t[0]} ${t[1]} ${t[2]}) translate(${t[5]} ${value}) scale(${t[3]} ${t[4]}) translate(${-t[5]} ${-value}) translate(${t[7]} ${t[8]})`
                         currT = `${t[0]} ${t[1]} ${t[2]} ${t[3]} ${t[4]} ${t[5]} ${value} ${t[7]} ${t[8]}`
                    break;
            }

            if(currT.length > 0 && valueT.length > 0 ){
                this.updateAttribute(Attributes.transform,valueT,container) 
                 this.updateAttribute(Attributes.curTransform,currT,container) 
            }
        }
    }
   
    handleShadow(k,value){
        switch(k){
            case "shadow":
            case "shadowRadius":
            case "shadowOffsetX":
            case "shadowOffsetY":
                this.updateAttribute(Attributes[k],value,this.getElement(Attributes.elements.shadow)) 
                break;
            case "shadowOffset":
                this.updateAttribute(Attributes.shadowOffsetX,value,this.getElement(Attributes.elements.shadow)) 
                this.updateAttribute(Attributes.shadowOffsetY,value,this.getElement(Attributes.elements.shadow)) 
                break;
            case "shadowRect":
                let e = this.getElement(Attributes.elements.filter)
                this.updateAttribute(Attributes.shadowRect.units,value.units,e)
                this.updateAttribute(Attributes.shadowRect.x,value.x,e)
                this.updateAttribute(Attributes.shadowRect.y,value.y,e)
                this.updateAttribute(Attributes.shadowRect.w,value.w,e)
                this.updateAttribute(Attributes.shadowRect.h,value.h,e) 
                break
        }
    }
    getElement(id){
        return this.myRef.current.querySelector(`#${this.keyElemet}${id}${this.props.painterKey}`)
     }
    updateAttribute(k,value,element){
        if(element) element.setAttribute(k,value)
    }
    getAttribute(k,element){
        if(element)  {
            let v = element.getAttribute(k)
            return  v ? v : ""
        }
        return ""
    }

    render(){
        return <TextWeb ref={this.myRef} {...this.props} />
    }
}