define(['durandal/system', 'services/logger', 'config', 'breeze', 'knockout'], function (system, logger, config, breeze, ko) {

    var Validator = breeze.Validator,
        referenceCheckValidator,
        nulloDate = new Date(1900, 0, 1);

    var orderBy = {
        health: 'id',
        disease: 'id',
        oil: 'id'
    };

    var entityNames = {
        direction: 'Direction',
        health: 'Health',
        user: 'User',
        disease: 'Disease',
        oil: 'Oil',
        tag: 'Tag',
        tagDisease: 'TagDisease',
        tagOil: 'TagOil'
    };

    var model = {
        applyValidators: applyValidators,
        configureMetadataStore: configureMetadataStore,
        createNullos: createNullos,
        entityNames: entityNames,
        orderBy: orderBy
    };

    return model;

    //#region internal methods
    function configureMetadataStore(metadataStore) {
        metadataStore.registerEntityTypeCtor('User', function () { this.isPartial = true; }, userInitializer);
        metadataStore.registerEntityTypeCtor('Oil', function () { this.isPartial = true; }, oilInitializer);
        metadataStore.registerEntityTypeCtor('Health', function () { this.isPartial = true; }, healthInitializer);
        metadataStore.registerEntityTypeCtor('Disease', function () { this.isPartial = true; }, diseaseInitializer);
        metadataStore.registerEntityTypeCtor('TagDisease', function () { this.isPartial = true; }, tagDiseaseInitializer);

        /*  metadataStore.registerEntityTypeCtor('Disease', function () { this.isPartial = true; }, personInitializer);
        metadataStore.registerEntityTypeCtor(
            'Oil', function () { this.isPartial = true; }, personInitializer);
        metadataStore.registerEntityTypeCtor(
            'User', function () { this.isPartial = true; }, personInitializer);*/
        metadataStore.registerEntityTypeCtor(
            'Tag', function () { this.isPartial = true; }, tagInitializer);

        referenceCheckValidator = createReferenceCheckValidator();
        Validator.register(referenceCheckValidator);
        log('Validators registered');
    }

    function createNullos(manager) {
        var unchanged = breeze.EntityState.Unchanged;
        
//        createNullo(entityNames.health);
//        createNullo(entityNames.tag);
//        createNullo(entityNames.oil);
//        createNullo(entityNames.disease);

        function createNullo(entityName, values) {
            var initialValues = values || { name: ' [Select a ' + entityName.toLowerCase() + ']' };
            return manager.createEntity(entityName, initialValues, unchanged);
        }
    }

    function createReferenceCheckValidator() {
        var name = 'realReferenceObject';
        var ctx = { messageTemplate: 'Missing %displayName%' };
        var val = new Validator(name, valFunction, ctx);
        log('Validators created', val);
        return val;

        function valFunction(value, context) {
            return value ? value.id() !== 0 : true;
        }
    }

    function applyValidators(metadataStore) {
        /*var types = ['room', 'track', 'timeSlot', 'speaker'];
        types.forEach(addValidator);
        log('Validators applied', types, types);

        function addValidator(propertyName) {
            var sessionType = metadataStore.getEntityType('Session');
            sessionType.getProperty(propertyName).validators.push(referenceCheckValidator);
        }*/
    }

    function userInitializer(user) {
        if (user.id() === 0) {
            user.isPartial(false); // created sessions are never partial
        }
//        user.password = ko.observable();
    }

    function oilInitializer(oil) {
        if (oil.id() === 0) {
            oil.isPartial(false); // created sessions are never partial
        }

        oil.type   = 'oil';
        oil.tagMap = 'TagOil';

        tagControl.apply(oil);
    }

    function healthInitializer(health) {
        if (health.id() === 0) {
            health.isPartial(false); // created sessions are never partial
        }
        /*health.tagsFormatted = ko.computed({
            read: function () {
                var text = session.tags();
                return text ? text.replace(/\|/g, ', ') : text;
            },
            write: function (value) {
                session.tags(value.replace(/\, /g, '|'));
            }
        });*/
    }


    function tagControl(){
        var self = this;
        //# Tags
        self.selectedTags = ko.computed({
            read: function () {
                var selected = ko.observableArray([]);
                if(self){
                    $.each(self.tags(), function(index, tag_map){
                        if(!tag_map.tag()){
                            tag_map.entityAspect.setDeleted();
                        }else{
                            selected.push({id:tag_map.tag().id(), text: tag_map.tag().name(), map_id: tag_map.id()});
                        }

                    });
                }
                return selected();
            },
            write: function (value) {
                console.log(value)
            }
        });

        self.selectedTagValues = ko.computed({
            read: function () {
                var selected = [];
                if(self){
                    $.each(self.tags(), function(index, tag_map){
                        if(!tag_map.tag()){
                            tag_map.entityAspect.setDeleted();
                        }else{
                            selected.push(tag_map.tag().id());
                        }
                    });
                }
                return selected;
            },
            write: function (value) {
                console.log(value)
            }
        });

        self.addTag = function(tag){
            console.log(tag)
           // self.tags.push(tag);
        };

        self.removeTag = function(tag){
            var tagMap = ko.utils.arrayFirst(self.tags(), function(item){
                return item.id() == tag.map_id;
            });
            self.tags.remove(tagMap);
            tagMap.entityAspect.setDeleted();
        };

        self.tags.subscribe(function (value) {
           debugger;
        });
        //# /Tags
    };

    function diseaseInitializer(disease) {
        if (disease.id() === 0) {
            disease.isPartial(false); // created sessions are never partial
        }

        disease.type   = 'disease';
        disease.tagMap = 'TagDisease';

        tagControl.apply(disease);
    }

    function tagDiseaseInitializer(tagDisease) {
        console.log(tagDisease);
    }

    function tagInitializer(tag) {
        tag.text = ko.observable(tag.name());
    }

    function personInitializer(person) {
        if (person.id() === 0) {
            person.isPartial(false); // created persons are never partial
        }
        person.fullName = ko.computed(function () {
            var fn = person.firstName();
            var ln = person.lastName();
            return ln ? fn + ' ' + ln : fn;
        });
        person.imageName = ko.computed(function () {
            return makeImageName(person.imageSource());
        });
    };

    function timeSlotInitializer(timeSlot) {
        timeSlot.name = ko.computed(function () {
            var start = timeSlot.start();
            var value = ((start - nulloDate) === 0) ?
                '[Select a timeslot]' :
                (start && moment.utc(start).isValid()) ?
                    moment.utc(start).format('ddd hh:mm a') : '[Unknown]';
            return value;
        });
    }

    function makeImageName (source) {
        return imageSettings.imageBasePath +
            (source || imageSettings.unknownPersonImageSource);
    }

    function log(msg, data, showToast) {
        logger.log(msg, data, system.getModuleId(model), showToast);
    }
    //#endregion
});