/**
 * Created by rburson on 12/28/16.
 */

import {StringDictionary, ObjUtil, Base64} from 'catavolt-sdk'

export class CvDisplayProperties {

    private static PARAM_DELIM:string = '~';
    private static VALUE_DELIM:string = ':';
    private static ARRAY_ITEM_DELIM:string = ',';

    private _properties:StringDictionary;
    
    constructor(properties?:StringDictionary){
        this._properties = properties ? properties : {};
    }
    
    getAndUpdate(name:string, value:any):CvDisplayProperties {
        const newDisplayProps = ObjUtil.addAllProps(this._properties, {});
        newDisplayProps[name] = value;
        return new CvDisplayProperties(newDisplayProps);
    }
    
    getProperty(name:string):any {
        return this._properties[name];
    }

    getAndRemove(name:string):CvDisplayProperties {
        const newDisplayProps = ObjUtil.addAllProps(this._properties, {});
        delete newDisplayProps[name];
        return new CvDisplayProperties(newDisplayProps);
    }
    
    serializeProperties():string {
        var params = [];
        for(var p in this._properties)
            if (this._properties.hasOwnProperty(p)) {
                params.push(p + CvDisplayProperties.VALUE_DELIM + this.encodePropValue(this._properties[p]));
            }
        return params.join(CvDisplayProperties.PARAM_DELIM);
    }

    publishToListeners(displayPropChangeListeners?:Array<(displayProperties:CvDisplayProperties)=>void>) {
        displayPropChangeListeners.forEach((listener)=>{ listener(this);});
    }
    
    static deserializeProperties(propString:string):CvDisplayProperties {
        const params:Array<string> = propString.split(CvDisplayProperties.PARAM_DELIM);
        const properties = {};
        params.forEach((paramValues:string)=>{
            const values = paramValues.split(CvDisplayProperties.VALUE_DELIM);
            if(values.length > 0) {
                if(values.length > 1) {
                    properties[values[0]] = CvDisplayProperties.decodePropValue(values[1]);
                } else {
                    properties[values[0]] = null;
                }
            }
        });
        return new CvDisplayProperties(properties);
    }

    /*
        Note: we use Base64 to encode property value and any reserved chars we are using for delimiters
     */
    private encodePropValue(propValue:any):string {
        if(propValue == null || propValue == undefined) {
            return '';
        } else {
            return Array.isArray(propValue) ?
                CvDisplayProperties.ARRAY_ITEM_DELIM + propValue.map((v)=>{ return Base64.encode(String(v)); }).join(CvDisplayProperties.ARRAY_ITEM_DELIM)
                : Base64.encode(String(propValue));
        }
    }

    private static decodePropValue(propValue:string):any {
        if(propValue == null || propValue == undefined || propValue == '') {
            return null;
        } else {
            if(propValue.substr(0, 1) === ',') {
                if(propValue.length > 1) {
                    return propValue.substr(1).split(CvDisplayProperties.ARRAY_ITEM_DELIM).map((v)=>{ return Base64.decode(v)});
                } else {
                    return [];
                }
            } else {
                return Base64.decode(propValue);
            }
        }
    }
}


