define( ['knockout', 'config', 'Q', 'breeze', 'services/breeze.knockout', 'breeze-labs/breeze.metadata-helper'], function(ko, config, Q, breeze){
    breeze.core.config.initializeAdapterInstances({
        modelLibrary: "knockout"
    });




    var DataService = function() {
        var self = this;

        self.manager = new breeze.EntityManager(config.remoteServiceName);



        self.getHealths = function(where, fetchStrategy) {
            fetchStrategy = fetchStrategy || breeze.FetchStrategy.FromServer;
            var query = new breeze.EntityQuery()
                .from('Healths')
                .expand(['diseases', 'diseases.tags']);
            if (where) {
                query = query.where(where);
            }

            return query.using(self.manager).using(fetchStrategy).execute();
        }

        self.getOils = function(where, fetchStrategy) {
            fetchStrategy = fetchStrategy || breeze.FetchStrategy.FromServer;
            var query = new breeze.EntityQuery()
                .from('Oils');            if (where) {
                query = query.where(where);
            }

            return query.using(self.manager).using(fetchStrategy).execute();
        }

        self.getUsers = function(where, fetchStrategy) {
            fetchStrategy = fetchStrategy || breeze.FetchStrategy.FromServer;
            var query = new breeze.EntityQuery()
                .from('Users');
            if (where) {
                query = query.where(where);
            }

            return query.using(self.manager).using(fetchStrategy).execute();
        }

        self.getTags = function(where, fetchStrategy) {
            fetchStrategy = fetchStrategy || breeze.FetchStrategy.FromServer;
            var query = new breeze.EntityQuery()
                .from('Tags');
            if (where) {
                query = query.where(new breeze.Predicate('name', 'startswith', where));
            }

            return query.using(self.manager).using(fetchStrategy).execute();
        }

        self.createUser = function(user) {
            user = user || {};
            return self.manager.createEntity('User',
                {name: ko.unwrap(user.name), email: ko.unwrap(user.email), password: ko.unwrap(user.password)});
        }

        self.createOil = function(oil) {
            oil = oil || {};
            return self.manager.createEntity('Oil',
                {name: ko.unwrap(oil.name), description: ko.unwrap(oil.description)});
        }

        self.createHealth = function(health) {
            health = health || {};
            return self.manager.createEntity('Health',
                {name: ko.unwrap(health.name), description: ko.unwrap(health.description)});
        }

        self.createDisease = function(disease) {
            disease = disease || {};
            return self.manager.createEntity('Disease',
                {name: ko.unwrap(disease.name), description: ko.unwrap(disease.description), health: ko.unwrap(disease.health), tags: []});
        }

        self.createTag = function(tag) {
            tag = tag || {};
            return self.manager.createEntity('Tag',
                {name: tag.name, disease: tag.name});
        }

        self.createTagMap = function(data, type) {
            return self.manager.createEntity('Tag' + type, data);
        }

        self.createToken = function(token) {
            token = token || {};
            return self.manager.createEntity('Token',
                {token: ko.unwrap(token.token), allowed: ko.unwrap(token.allowed), restricted: ko.unwrap(token.restricted), user: ko.unwrap(token.user)});
        }

        //error: "An exception occurred while executing 'INSERT INTO tokens (token, allowed, restricted, created, user_id) VALUES (?, ?, ?, ?, ?)' with params [null, "smartext.com\n192.168.0.1", "", 1411566407, 1]:↵↵SQLSTATE[23000]: Integrity constraint violation: 19 tokens.token may not be NULL"

        self.removeDisease = function(disease) {
            disease.entityAspect.setDeleted();
        }

        self.removeTag = function(item, tag) {
            var deferred = Q.defer();
            var func = 'get' + item.entityType.shortName + 'TagMap';

            self[func](item, tag).then(function(data){
                data.results[0].entityAspect.setDeleted();
                deferred.resolve();
            }).fail(function(error){
                deferred.reject(error);
            });
            return deferred.promise;
        }

        self.removeHealth = function(health) {
            health.entityAspect.setDeleted();
        }

        self.saveChanges = function() {
            return self.manager.saveChanges();
        }

        self.findHealthById = function(healthId) {
            var deferred = Q.defer();
            self.getHealths(new breeze.Predicate('id', '==', healthId),
                    breeze.FetchStrategy.FromLocalCache).then(function(data) {
                    deferred.resolve(data.results[0]);
                })
            return deferred.promise;
        }

        self.findTag = function(tagId) {
            var deferred = Q.defer();
            self.getTags(new breeze.Predicate('id', '==', tagId),
                    breeze.FetchStrategy.FromLocalCache).then(function(data) {
                    deferred.resolve(data.results);
                }).fail(function(error){
                    deferred.reject(error);
                });
            return deferred.promise;
        }

        self.getTagItems = function(id, type) {
            var query = new breeze.EntityQuery()
                .from('Tags')
                .expand(type)
                .where('id', 'eq', id);

            return query.using(self.manager).using(breeze.FetchStrategy.FromServer).execute();
        }

        self.getTagById = function(id) {
            var query = new breeze.EntityQuery()
                .from('Tags')
                .where('id', 'eq', id);

            return query.using(self.manager).using(breeze.FetchStrategy.FromServer).execute();
        }

        self.getTagMapById = function(id) {
            var query = new breeze.EntityQuery()
                .from('TagsDiseases')
                .where('id', 'eq', id);

            return query.using(self.manager).using(breeze.FetchStrategy.FromServer).execute();
        }

        self.getDiseaseTagMap = function(disease, tag) {
            var query = new breeze.EntityQuery()
                .from('TagsDiseases')
                .where('diseaseId', 'eq', disease.id())
                .where('tagId', 'eq', tag.id);

            return query.using(self.manager).using(breeze.FetchStrategy.FromServer).execute();
        }

        self.getOilTagMap = function(oil, tag) {
            var query = new breeze.EntityQuery()
                .from('TagsOils')
                .where('oilId', 'eq', oil.id())
                .where('tagId', 'eq', tag.id);

            return query.using(self.manager).using(breeze.FetchStrategy.FromServer).execute();
        }

        self.getTagOilMapById = function(id) {
            var query = new breeze.EntityQuery()
                .from('TagsOils')
                .where('id', 'eq', id);

            return query.using(self.manager).using(breeze.FetchStrategy.FromServer).execute();
        }

        self.findHealth = function(id){
            var query = new breeze.EntityQuery()
                .from('Healths')
                .expand(['diseases', 'diseases.tags', 'diseases.tags.tag'])
                .where('id', 'eq', id);

            return query.using(self.manager).using(breeze.FetchStrategy.FromServer).execute();
        }

        self.findOil = function(id){
            var query = new breeze.EntityQuery()
                .from('Oils')
                .expand(['tags', 'tags.tag'])
                .where('id', 'eq', id);

            return query.using(self.manager).using(breeze.FetchStrategy.FromServer).execute();
        }

        self.findUser = function(id){
            var query = new breeze.EntityQuery()
                .from('Users')
                .expand(['tokens'])
                .where('id', 'eq', id)
                    .orderBy('tokens.id DESC')
                ;

            return query.using(self.manager).using(breeze.FetchStrategy.FromServer).execute();
        }

        self.remove = function(item){
            item.entityAspect.setDeleted();
        }
    }

    return new DataService;
});