coreFramework.provider('Entity', function () {
    var config = {};

    this.setConfig = function (params) {
        angular.extend(config, params);
    };

    this.$get = ['$q', '$parse', 'Restangular', 'Message', 'SharedModel', function ($q, $parse, Restangular, Message, SharedModel) {

        var _http = {
            get: function (url, params, headers) {

                var deferred = $q.defer();
                Restangular.oneUrl('url', url).get(params || null, headers || null).then(function (response) {
                    deferred.resolve(response);
                }, function (errors) {
                    deferred.reject(errors);
                });
                return deferred.promise;

            },
            update: function (url, data, params, headers) {

                var deferred = $q.defer();
                Restangular.oneUrl('url', url).patch(data, params || null, headers || null).then(function (response) {
                    deferred.resolve(response);
                }, function (errors) {
                    deferred.reject(errors);
                });
                return deferred.promise;

            },
            delete: function (url, params, headers) {

                var deferred = $q.defer();
                Restangular.oneUrl('url', url).remove(params || null, headers || null).then(function (response) {
                    deferred.resolve(response);
                }, function (errors) {
                    deferred.reject(errors);
                });
                return deferred.promise;

            },
            create: function (url, data, params, headers) {

                var deferred = $q.defer();
                Restangular.allUrl('url', url).post(data, params || null, headers || null).then(function(response) {
                    deferred.resolve(response);
                }, function (errors) {
                    deferred.reject(errors);
                });
                return deferred.promise;

            }
        };

        var _entity = {
            get: function (endpoint, id, params, headers) {

                var deferred = $q.defer();
                Restangular.one(endpoint, id).get(params || null, headers || null).then(function (response) {
                    deferred.resolve(response);
                }, function (errors) {
                    deferred.reject(errors);
                });
                return deferred.promise;

            },
            update: function (endpoint, id, data, params, headers) {

                var deferred = $q.defer();
                Restangular.one(endpoint, id).patch(data, params || null, headers || null).then(function (response) {
                    deferred.resolve(response);
                }, function (errors) {
                    deferred.reject(errors);
                });
                return deferred.promise;
                
            },
            delete: function (endpoint, id, params, headers) {

                var deferred = $q.defer();
                Restangular.one(endpoint, id).remove(params || null, headers || null).then(function (response) {
                    deferred.resolve(response);
                }, function (errors) {
                    deferred.reject(errors);
                });
                return deferred.promise;
                
            },
            create: function (endpoint, data, params, headers) {

                var deferred = $q.defer();
                Restangular.all(endpoint).post(data, params || null, headers || null).then(function (response) {
                    deferred.resolve(response);
                }, function (errors) {
                    deferred.reject(errors);
                });
                return deferred.promise;

            }
        };

        var _entityShared = {
            get: function (list, endpoint, id) {

                var promiseList = list.map(function (item) {
                    var promise = _entity.get(endpoint, id, item.params && item.params.read, item.headers && item.headers.read);
                        promise.then(function (response) {
                            item.form.is_loading = false;
                            // $parse('data').assign(item, data);
                            item.data = response.data.originalElement;
                        });
                    return promise;
                });

                var promise = $q.all(promiseList);

                return promise;

            },
            update: function (list, endpoint, id) {

                var deferred = $q.defer();
                    deferred.reject();

                var dirtyList = list.filter(function (item) {
                    return item.form.is_dirty;
                });

                if (!dirtyList.length) {
                    return deferred.promise;
                }

                var validList = dirtyList.filter(function (item) {
                    return item.form.is_valid;
                });

                if (!validList.length) {
                    Message.send('There is an error in your content!', 'error');
                    return deferred.promise;
                }

                var promiseList = validList.map(function (item) {

                    item.form.is_loading = true;
                    var promise = _entity.update(endpoint, id, item.data, item.params && item.params.write, item.headers && item.headers.write);
                        promise.then(function (response) {
                            item.dataErrors = null;
                            item.form.is_loading = false;
                            item.form.is_dirty = false;
                        }, function (errors) {
                            item.dataErrors = errors.data;
                            item.form.is_loading = false;
                        });
                    return promise;

                });

                var promise = $q.all(promiseList);

                promise.then(function (response) {
                    Message.send('Saved!', 'success');
                }, function (errors) {
                    Message.send('Error!', 'error');
                });

                return promise;

            },
            delete: function (list, endpoint, id) {

                var deferred = $q.defer();
                    deferred.reject();

                var promiseList = list.map(function (item) {

                    var promise = _entity.delete(endpoint, id, item.params && item.params.write, item.headers && item.headers.write);
                    return promise;

                });

                var promise = $q.all(promiseList);

                promise.then(function (response) {
                    Message.send('Deleted!', 'success');
                }, function (errors) {
                    Message.send('Error!', 'error');
                });

                return promise;

            },
            create_old: function (list, endpoint) {

                var deferred = $q.defer();
                    deferred.reject();

                var dirtyList = list.filter(function (item) {
                    return item.form.is_dirty;
                });

                if (!dirtyList.length) {
                    return deferred.promise;
                }

                var validList = dirtyList.filter(function (item) {
                    return item.form.is_valid;
                });

                if (!validList.length) {
                    Message.send('There is an error in your content!', 'error');
                    return deferred.promise;
                }

                var promiseList = validList.map(function (item) {

                    item.form.is_loading = true;
                    var promise = _entity.create(endpoint, item.data, item.params && item.params.write, item.headers && item.headers.write);
                        promise.then(function () {
                            item.dataErrors = null;
                            item.form.is_loading = false;
                            item.form.is_dirty = false;
                        }, function (errors) {
                            console.log('error', errors);
                            item.dataErrors = errors.data;
                            item.form.is_loading = false;
                        });
                    return promise;

                });

                var promise = $q.all(promiseList);

                promise.then(function () {
                    Message.send('Saved!', 'success');
                }, function (errors) {
                    Message.send('Error!', 'error');
                });

                return promise;

            },
            create: function (list, endpoint) {

                var exitPromise = function (promise) {

                    promise.then(function () {
                        Message.send('Saved!', 'success');
                    }, function (errors) {
                        Message.send('Error!', 'error');
                    });

                    return promise;

                };

                var deferred = $q.defer();
                    deferred.reject();

                var dirtyList = list.filter(function (item) {
                    return item.form.is_dirty;
                });

                if (!dirtyList.length) {
                    return deferred.promise;
                }

                var validList = dirtyList.filter(function (item) {
                    return item.form.is_valid;
                });

                if (!validList.length) {
                    Message.send('There is an error in your content!', 'error');
                    return deferred.promise;
                }

                validList.forEach(function (item) {

                    item.form.is_loading = true;

                });

                var createEntity = validList.shift();
                var createPromise = (function (item) {
                    var promise = _entity.create(endpoint, item.data, item.params && item.params.write, item.headers && item.headers.write);
                        promise.then(function () {
                            item.dataErrors = null;
                            item.form.is_loading = false;
                            item.form.is_dirty = false;
                        }, function (errors) {
                            console.log('error', errors);
                            item.dataErrors = errors.data;
                            item.form.is_loading = false;
                        });
                    return promise;
                })(createEntity);

                if (!validList.length) {
                    return exitPromise($q.all([createPromise]));
                }

                var patchDeferred = $q.defer();

                createPromise.then(function (response) {

                    _http.get(response.headers('location'), createEntity.params && createEntity.params.read, createEntity.headers && createEntity.headers.read).then(function(response) {

                        var patchList = validList.map(function (item) {

                            var promise = _entity.update(endpoint, response.data.id, item.data, item.params && item.params.write, item.headers && item.headers.write);
                                promise.then(function () {
                                    item.dataErrors = null;
                                    item.form.is_loading = false;
                                    item.form.is_dirty = false;
                                }, function (errors) {
                                    console.log('error', errors);
                                    item.dataErrors = errors.data;
                                    item.form.is_loading = false;
                                });
                            return promise;

                        });

                        $q.all(patchList).then(function (response) {
                            patchDeferred.resolve(response);
                        }, function (errors) {
                            patchDeferred.reject(errors);
                        });

                    }, function (errors) {
                        patchDeferred.reject(errors);
                    });

                }, function (errors) {
                    patchDeferred.reject(errors);
                });
                
                return exitPromise($q.all([createPromise, patchDeferred.promise]));

            }
        };

        return {
            model: function (endpoint, id) {
                var _self = {
                    id: id || null,
                    api: endpoint,
                    model: {}
                };
                _self.get = function (params, headers) {
                    var promise = _entity.get(_self.api, _self.id, params, headers);
                        promise.then(function (response) {
                            // _self.model = response.data.originalElement;
                            angular.extend(_self.model, response.data.originalElement)
                            // $parse('model').assign(_self, response.data.originalElement);
                        });
                    return promise;
                }
                _self.update = function (params, headers) {
                    return _entity.update(_self.api, _self.id, _self.model, params, headers);
                }
                _self.delete = function (params, headers) {
                    return _entity.delete(_self.api, _self.id, params, headers);
                }
                _self.create = function (params, headers) {
                    return _entity.create(_self.api, _self.model, params, headers);
                }
                return _self;
            },
            shared: function (endpoint, id) {
                var _self = {
                    id: id || null,
                    api: endpoint,
                    model: SharedModel(),
                    listeners: {}
                };
                _self.on = function (event, callback) {
                    _self.listeners[event] = _self.listeners[event] || [];
                    _self.listeners[event].push(callback);
                };
                _self.get = function (index) {
                    var promise = _entityShared.get(angular.isDefined(index) ? [_self.model.list[index]] : _self.model.list, _self.api, _self.id);
                        promise.then(function () {
                            _self.listeners['loaded'] && _self.listeners['loaded'].forEach(function (callback) {
                                callback();
                            });
                        });
                    return promise;
                };
                _self.update = function () {
                    return _entityShared.update(_self.model.list, _self.api, _self.id);
                };
                _self.delete = function () {
                    return _entityShared.delete(_self.model.list, _self.api, _self.id);
                };
                _self.create = function () {
                    return _entityShared.create(_self.model.list, _self.api);
                };
                return _self;
            },
            getUrl: function (url, params, headers) {
                return _http.get(url, params, headers);
            },
            postUrl: function (url, data, params, headers) {
                return _http.create(url, data, params, headers);
            },
            patchUrl: function (url, data, params, headers) {
                return _http.update(url, data, params, headers);
            },
            deleteUrl: function (url, params, headers) {
                return _http.delete(url, params, headers);
            }
        };

    }];
});
