var StructrRESTLoader = Namespace.declare("tla.EAM.layer1.OnceServices",
    class StructrRESTLoader {
        static start() {
            //            var Structr = window["Structr"] = window["Structr"] || new This();
        }
        constructor() {
            this.headers = {};
            Thinglish.addConstant(this, "restBasePath", "/structr/rest/");
            Thinglish.addConstant(this, "defaultServer", "http://structr.cerulean.it:6082");
            Thinglish.addConstant(this, "defaultRestView", "default");
            Thinglish.addConstant(this, "uiRestView", "ui");
            Thinglish.addConstant(this, "defaultView", this.uiRestView);

            Thinglish.addConstant(StructrRESTLoader, "defaultUser", "structrClientFremium");
            Thinglish.addConstant(StructrRESTLoader, "defaultPassword", "geheim");

            //Thinglish.implement(this, Loader);

        }

        init() {
            return this;
        }

        load(namespace) {
            console.error("Not yet Implemented");
            //@todo use ONCE.call
        }

        getIOR(structrType, id) {
            var ior = new IOR();
            ior.loader = this;
            ior.objectID = id;
            if (!structrType) {
                structrType = id;
                ior.objectID = null;
            } else {
                structrType += "/" + this.defaultView;
            }
            ior.credentials = { "user": StructrRESTLoader.defaultUser, "password": StructrRESTLoader.defaultPassword };

            ior.init(this.namespace2path(structrType));
            ior.headers = ior.loader.headers;
            ior.HTTPmethod = "GET";
            return ior;
        }

        namespace2path(namespace) {
            return this.defaultServer + this.restBasePath + namespace;
        }

        path2namespace(path) {
            var base = this.defaultServer + this.restBasePath;
            var i = path.indexOf(base);
            if (i == -1)
                return path;
            i = i + base.length;
            var namespace = path.substring(i);

            i = path.indexOf("/");
            if (i == -1)
                return path;



            return namespace;
        }


        checkLoader(object) {
            console.error("Not yet Implemented");
        }

    }
);

var StructrES6Client = Namespace.declare("com.ceruleanCircle.EAM.5_ux",
    class StructrES6Client extends UcpComponent/**/ {
        static start() {
            var Structr = window["Structr"] = window["Structr"] || new this();
        }
        constructor() {
            super();
            var DefaultStructrRESTLoader = new StructrRESTLoader();
            Thinglish.addConstant(this, "restBasePath", DefaultStructrRESTLoader.restBasePath);
            Thinglish.addConstant(this, "defaultServer", DefaultStructrRESTLoader.defaultServer);
            Thinglish.addConstant(this, "defaultRestView", DefaultStructrRESTLoader.defaultRestView);
            Thinglish.addConstant(this, "uiRestView", DefaultStructrRESTLoader.uiRestView);

            var cache = new IndexedObjects().init("id");
        }

        create(type, data) {
            var ior = new StructrRESTLoader().getIOR(type, id);
            ior.HTTPmethod = "POST";

        }
        retrieve() {}
        update(structrObject) {
            var ior = new StructrRESTLoader().getIOR(structrObject.type, structrObject.id);
            ior.HTTPmethod = "PUT";
            //            ior.url += "/"+structrObject.id;

            return this.call(ior, structrObject).then(
                response => {
                    console.log(response);
                });

        }
        delete(id) {}

        find(type, id, parameter) {
            var ior = new StructrRESTLoader().getIOR(type, id);

            console.log("Structr.find: looking for: ");
            var searching = id;
            if (!searching)
                searching = parameter;
            console.log(searching);

            return ONCE.call(ior, parameter).then(
                (response) => {
                    var resultObject = JSON.parse(response);
                    if (!resultObject.result.push)
                        resultObject.result = [resultObject.result];

                    var structrObjects = resultObject.result.map(
                        data => {
                            var structrObject = new StructrObject().init(this);
                            structrObject.properties = data;

                            structrObject.IOR = new StructrRESTLoader().getIOR(structrObject.structrType, structrObject.id);
                            structrObject.local.IOR = structrObject.IOR;
                            console.log("Structr.find: found " + structrObject.properties.name);
                            return structrObject;
                        }
                    );
                    return structrObjects;
                }).catch(
                error => {
                    console.error(error);
                });
        };

    }
);



var StructrObject = Namespace.declare("com.ceruleanCircle.EAM.5_ux.StructrES6Client",
    class StructrObject extends UcpModel {
        constructor() {
            super();
            //Thinglish.implement(this, Model);            
        }

        get properties() { return this._private.properties; }
        set properties(data) {
            super.properties = data;
            if (!this._private.properties) return this;

            Thinglish.initType(this, "org.structr.Schema." + this._private.properties.type);
            this.structrType = this._private.properties.type;
            this.name = this._private.properties.name;

            if (!this.structrType)
                this.structrType = data.id;


            // identify deep Structr Objects

            var value = null;
            for (var p in this._private.properties) {
                if (p[0] !== "_") {
                    value = this._private.properties[p];
                    if (value && !value.type && ((value.id) || (value.length == 32 && p !== "id"))) {
                        if (!value.id)
                            value = { id: value };

                        var so = new StructrObject().init(this);
                        so.properties = value;
                        //                        console.log(p);
                        this._private.properties[p] = so;
                    }
                    if (Array.isArray(value)) {
                        if (value.length > 0) {
                            //  console.log(p,value);
                            this._private.properties[p] = value.map(
                                value => {
                                    var so = new StructrObject().init(this.ucpComponent);
                                    so.properties = value;
                                    return so
                                }
                            );
                            // console.log(this.properties[p]);
                        }
                    }
                }
            }


            // check if there is local corresponding Class Implementations

            if (this._private.properties.type) {
                var localInterfaces = Interface.discover().reduce(
                    (result, current) => {
                        if (current.name === this._private.properties.type) {
                            if (Array.isArray(result))
                                result.push(current);
                            else
                                result = [current];
                        } else
                        if (!Array.isArray(result)) return [];
                        return result;
                    });
                this.localObjects = new IndexedObjects();
                localInterfaces.forEach(
                    i => {
                        var impls = i.discover();
                        if (impls && impls.length > 0) {
                            var theImpl = new impls[0];
                            theImpl.properties = this;
                            this.localObjects.push(theImpl.init(this));
                            //this.controller.ucpComponentClass.Store.register()
                        }
                    });
                if (this.localObjects.length > 0)
                    return this.localObjects[0];
            }


            return this;
        }

        get local() {
            var local = null;
            if (this.localObjects && this.localObjects.getValues().length > 0)
                local = this.localObjects.getValues()[0];
            if (local)
                return local;
            return this;
        }

        get isLoaded() {
            if (!this.properties) return false;
            return (this.properties.type != null);
        }

        load() {
            var type = this.structrType;
            var prefix = "org.structr.Schema.";
            if (type.indexOf(prefix) != -1)
                type = type.substr(prefix.length);

            return Structr.find(type, this.id).then(
                result => {
                    if (result.length > 0) {
                        var data = result[0];
                        if (data) {
                            //this.isLoaded = true;
                            var so = this;
                            this.properties = data._private.properties;
                            so.IOR = data.IOR;
                            so.local.IOR = data.IOR;
                            return so.local;
                        }
                    }
                });
        }

        save() {
            var changeObject = this._changeLog;
            changeObject.id = this.id;

            return Structr.update(changeObject).then(
                result => {
                    this._changeLog = {};
                });
        }

    }
);