

import * as wjcCore from 'wijmo/wijmo';


import * as wjcSelf from 'wijmo/wijmo.react.base';
window['wijmo'] = window['wijmo'] || {};
window['wijmo']['react'] = window['wijmo']['react'] || {};
window['wijmo']['react']['base'] = wjcSelf;

/*
    *
    * Wijmo Library 5.20173.409
    * http://wijmo.com/
    *
    * Copyright(c) GrapeCity, Inc.  All rights reserved.
    *
    * Licensed under the GrapeCity Commercial License.
    * sales@wijmo.com
    * wijmo.com/products/wijmo-5/license/
    *
    */

import * as ReactDOM from 'react-dom';
import * as  React from 'react';





    /**
     * Base class for all Wijmo components for React.
     */
    export class ComponentBase extends React.Component<any, any> {
        //private _meta: _IReactComponentMeta;
        private _objPropHash: { [propName: string]: boolean } = {};
        controlType: any;
        props: any;
        constructor(props: any, controlType: any, meta?: any) {
            super(props);
            this.props = props;
            this.controlType = controlType;

            for (let objProp of (meta && (<_IReactComponentMeta>meta).objectProps || [])) {
                this._objPropHash[objProp] = true;
            }
        }

        render() {
            return React.createElement('div');
        }

        //mounts a new control onto a component
        componentDidMount() {
            // instantiate the control
            var host = <HTMLElement>ReactDOM.findDOMNode(this),
                control = new this.controlType(host),
                cprops = this.props;

            // initialize the control with properties and event handlers,
            // and the host element with the regular HTML properties
            var props = {};
            for (var prop in cprops) {
                if (prop in control) {

                    // save property to assign to control later
                    props[prop] = cprops[prop];

                } else {

                    // assign property to host element
                    switch (prop) {
                        case 'className':
                            wjcCore.addClass(host, cprops.className);
                            break;
                        case 'style':
                            wjcCore.setCss(host, cprops.style);
                            break;
                        default: // id, title, name, etc...
                            if (host[prop] != null) {
                                host[prop] = cprops[prop];
                            }
                            break;
                    }
                }
            }

            // apply saved props to control
            control.initialize(props);

            // fire initialize event
            if (wjcCore.isFunction(cprops.initialized)) {
                cprops.initialized(control);
            }

            // done creating the control
            return control;

        }

        // disposes of the control associated with a component
        componentWillUnmount() {
            this._getControl(this).dispose();
        }

        // updates the control properties to match its associated component
        shouldComponentUpdate(nextProps) {
            var ctl = this._getControl(this);
            this._copy(ctl, nextProps);
            return true;
        }

        private _getControl(component): any {
            var host = ReactDOM.findDOMNode(component);
            return wjcCore.Control.getControl(host);
        }

        private _copy(dst, src) {
            if (!(dst && src)) {
                return;
            }
            let ctrl;
            for (var p in src) {
                var value = src[p],
                    isValid = p in dst || p == 'className' || p == 'style'; // TFS 277044

                if (isValid && !this._isEvent(dst, p) && !this._sameValue(dst[p], value)) {
                    if (value == null) { // copy null/undefined
                        dst[p] = value;
                    } else if (p == 'className') { // copy className
                        if (dst.hostElement) {
                            wjcCore.addClass(dst.hostElement, src[p]);
                        }
                    } else if (p == 'style') { // copy style
                        if (dst.hostElement) {
                            wjcCore.setCss(dst.hostElement, src[p]);
                        }
                    } else if (wjcCore.isPrimitive(value) || // copy properties declared as PropertyType.Any in metadata
                        this._objPropHash[p] && dst === (ctrl || (ctrl = this._getControl(this)))) {
                        dst[p] = value;
                    } else if (wjcCore.isArray(value) && wjcCore.isArray(dst[p])) { // copy arrays (of equal size)
                        let dstArr = dst[p],
                            srcArr = value;
                        if (srcArr.length == dstArr.length) {
                            for (var i = 0; i < srcArr.length; i++) {
                                this._copy(dstArr[i], srcArr[i]);
                            }
                        }
                    } else if (wjcCore.isObject(value)) { // copy object content
                        this._copy(dst[p], src[p]);
                    }
                }
            }
        }

        // compares two objects by value
        private _sameValue(v1, v2): boolean {
            return v1 == v2 || wjcCore.DateTime.equals(v1, v2);
        }

        private _isEvent(ctrl: any, propName: string): boolean {
            let propVal = ctrl && ctrl[propName];
            return propVal != null && propVal instanceof wjcCore.Event;
        }

    }

    interface _IReactComponentMeta {
        // Names of properties declared in metadata with PropertyType.Any.
        objectProps: string[]
    }


