define(['jquery', 'tools/tools', 'tools/validate', 'tnc/tnc-layer', 'tnc/tnc-transition', 'tools/jq-tools', 'tools/tools-3d', 'tnc/tnc-tools', 'tools/urls', 'bluebird'],
    function() {
        'use strict';
        // var $ = require('jquery');
        var tools = require('tools/tools');
        var urls = require('tools/urls');
        var validate = require('tools/validate');
        var TncLayer = require('tnc/tnc-layer');
        var TncTransition = require('tnc/tnc-transition');
        var jqTools = require('tools/jq-tools');
        // var tools3d = require('tools/tools-3d');
        var tncTools = require('tnc/tnc-tools');
        var arrays = require('tools/arrays');
        var Promise = require('bluebird');
        var forEach = arrays.forEach;

        var $new = jqTools.$new;
        var $newCss = jqTools.$newCss;

        //var log = console.log.bind(console);
        var log = tools.log;
        var format = tools.format;

        var getStr = validate.getStr;
        var getNum = validate.getNum;
        // var isNumber = validate.isNumber;
        var getColor = validate.getColor;

        var resourceUrl = tncTools.resourceUrl;
        // var isUrl = tncTools.isUrl;
        var del = tools.del;

        function TncTemplate(scope, settings) {
            this.init(scope, settings);
        }

        TncTemplate.prototype.isTemplateRefresh = false;

        TncTemplate.prototype.init = function(scope, settings) {
            var ok = (settings && typeof settings === 'object');
            if (!ok) {
                log('error: TncTemplate: settings is not an object');
            }

            var self = this;
            self.scope = scope || {};
            self.settings = settings || {};
            self.id = tools.guid();
            self.folder = getStr(self.settings.folder, '');
            self.page = getStr(self.settings.page, '');

            self.stillPlaying = true;

            var params = urls.getQueryParams();
            self.enableEdit = params.edit ? true : false;
            self.exampleItems = params.exampleitems ? true : false;
            self.novideo = params.novideo ? true : false;

            self.resolution = getStr(params.resolution, '');
            self.resolutionX = 0;
            self.resolutionY = 0;

            var resolutionArr = self.resolution.split('x');
            if (resolutionArr.length === 2) {
                self.resolutionX = getNum(resolutionArr[0]);
                self.resolutionY = getNum(resolutionArr[1]);
            }

            self.css = self.settings.css;
            self.aspectRatio = getStr(self.settings.aspectRatio, '');
            self.aspectRatioNumeric = null;

            var p = self.aspectRatio.split('/');
            if (p.length > 1) {
                self.aspectRatioNumeric = getNum(p[0].trim(), 1) / getNum(p[1].trim(), 1);
            }

            self.backgroundImage = getStr(self.settings.backgroundImage, '');
            self.backgroundColor = getColor(self.settings.backgroundColor, 'transparent');
            self.templateVersion = getNum(self.settings.templateVersion, 0);

            self.transition = new TncTransition(self.settings.transition, self);
            self.duration = getNum(self.settings.duration, 0);
            self.durationExpired = false;

            self.isPlaying = false;
            self.paused = false;

            self.layers = [];

            for (var i = 0; i < self.settings.layers.length; i += 1) {
                var layerScope = { template: self };

                var layer = new TncLayer(layerScope, self.settings.layers[i]);
                self.layers.push(layer);
            }

            TncTemplate.prototype.isTemplateRefresh = false;
        };

        TncTemplate.prototype.sendSocketReady = function () {
            window.parent.postMessage(JSON.stringify("templateReady"), "*");
        };

        TncTemplate.prototype.sendStillPlaying = function() {
            var self = this;
            self.scope.sendMessageCefhost('status', {
                'still-playing': self.stillPlaying,
                id: self.id
            });
            // log({
            //     'still-playing': self.stillPlaying,
            //     id: self.id
            // });
        };

        TncTemplate.prototype.addLayer = function(settings) {
            var self = this;
            var layerScope = { template: self };
            var layer = new TncLayer(layerScope, settings);
            self.layers.push(layer);
            layer.load(self.$content, true);
            layer.play();
            layer.setActive();
        };

        TncTemplate.prototype.deleteLayer = function(layerId) {
            var self = this;
            var index = -1;

            for (var i = 0; i < self.layers.length; i += 1) {
                if (self.layers[i].id === layerId) {
                    index = i;
                    break;
                }
            }

            if (index > -1) {
                self.layers[i].unload();
                self.layers.splice(index, 1);
            } else {
                log(format('Layer {0} not found, not deleted', layerId));
            }
        };

        TncTemplate.prototype.load = function($parent, callback, reload) {
            var self = this;
            //var reload = reload;


            if (TncLayer.prototype.activeLayer) {
                TncLayer.prototype.activeLayer.deactivate(true);
            }

            // force reload whole template
            if (reload && self.$element) {
                self.$element.remove();
                self.$element = null;
            }

            if (!self.$element) {
                self.$element = $new('div', $parent);
                self.$element.addClass('tncTemplate');

                self.$panel = $new('div', self.$element);
                self.$panel.css({
                    opacity: 0.001
                });
                self.$panel.addClass('tncTemplatePanel');

                self.$frame = $new('iframe', self.$panel);
                self.$frame.addClass('tncTemplateFrame');

                var iframeInitialized = false;

                var iframeReady = function() {
                    if (!iframeInitialized) {
                        iframeInitialized = true;


                        // var $html = self.$frame.contents().find('html');

                        var setFontScaleRelative = function() {
                            var $ = window.jQuery;
                            //								var setFontScale = function() {
                            //									var defaultSize = 16;
                            //									var fs = Math.round(defaultSize * (window.innerWidth / 1920));
                            //									//$('html').css('font-size', fs + 'px');
                            //									$html.css('font-size', fs + 'px');
                            //								};
                            /*
								var spheresCollide = function(s1, s2) {
									//Check if the distance between the spheres centers is less than the sum of their radius.
									var radius = s1.radius + s2.radius;
									var dist = s1.position - s2.position;
									return dist < radius;
								};*/

                            var scaleToFit = function(currentSize, maxSize, scaleUp) {
                                var newSize = currentSize;
                                var ratioX = maxSize[0] / currentSize[0];
                                var ratioY = maxSize[1] / currentSize[1];
                                var ratio = Math.min(ratioX, ratioY);

                                if (ratio < 1.0 || scaleUp) {
                                    newSize[0] = Math.floor(currentSize[0]) * ratio;
                                    newSize[1] = Math.floor(currentSize[1]) * ratio;
                                }
                                return {
                                    size: newSize,
                                    ratio: ratio
                                };
                            };

                            var getCenterOffset = function(size, targetSize) {
                                return [((targetSize[0] - size[0]) / 2), ((targetSize[1] - size[1]) / 2)];
                            };

                            var setWindowScale = function() {
                                var screenWidth = self.resolutionX; // screen.width || window.innerWidth || 1920;
                                var screenHeight = self.resolutionY; // screen.height || window.innerHeight || 1080;

                                //screenWidth /= 1.5;
                                //screenHeight /= 1.5;
                                /*
                                    var hscale = (window.innerWidth / screenWidth); //$(window).width() / $('body').width();
									//var vscale = (window.innerHeight / screenHeight);
									//var ratio = Math.min(hscale, vscale);

                                    //var zoom = scale * 100;
                                    //document.body.style.zoom = zoom+'%';
                                    //var vscale = (window.innerHeight / screenHeight);
                                    var theight = window.innerWidth * (1/ratio);
									// var twidth = window.innerHeight * (1/ratio);
                                    var theight = $(window).height() * (1/hscale);

                                    $('body').css({
                                        'width': $(window).width() * (1/hscale),
                                        'height': theight,
                                        'transform-origin': '0 0',
                                        'transform': 'scale(' + hscale + ')'
                                    });*/

                                var current = [screenWidth, screenHeight];
                                var max = [window.innerWidth, window.innerHeight];
                                var scale = scaleToFit(current, max, true);
                                var offset = getCenterOffset(scale.size, max);

                                $('body').css({
                                    'width': screenWidth, //$(window).width() * (1 / hscale),
                                    'height': screenHeight,
                                    'transform-origin': '0 0',
                                    'transform': 'translate(' + offset[0] + 'px, ' + offset[1] + 'px) scale(' + scale.ratio + ')'
                                });

                                //console.log(newSize, offset)

                                //console.log('Window scale: ', hscale, window.innerWidth);
                            };

                            if (self.resolutionX > 0 && self.resolutionY > 0) {
                                $(window).resize(function() {
                                    //setFontScale();
                                    setWindowScale();
                                });

                                setTimeout(function() {
                                    // Fire it when the page first loads:
                                    //setFontScale();
                                    setWindowScale();
                                }, 500);
                            }
                        };
                        setFontScaleRelative();

                        self.$body = self.$frame.contents().find('body');
                        self.$content = $new('div', self.$body);
                        self.$content.addClass('tncTemplateContent');

                        var doc = self.$body[0].ownerDocument;

                        // var win = doc.parentWindow || doc.defaultView;
                        // win.onerror = globalErrorHandler;

                        var $ = window.jQuery;
                        self.$doc = $(doc);

                        self.keyDownHandler = function(event) {
                            var handled = self.scope.globalKeydown(event.which);
                            if (handled)
                                event.preventDefault();
                        };

                        self.clickHandler = function(event) {
                            var handled = self.scope.globalClick(event);
                            if (handled)
                                event.preventDefault();
                        };

                        self.mouseDownHandler = function(event) {
                            var handled = self.scope.globalMousedown(event);
                            if (handled)
                                event.preventDefault();
                        };

                        // forward key events to main frame
                        self.$doc.on('keydown', self.keyDownHandler);
                        self.$doc.on('click', self.clickHandler);
                        self.$doc.on('mousedown', self.mouseDownHandler);

                        // Load template css here in the iframe
                        var $head = self.$frame.contents().find('head');
                        $newCss('theme/bootstrap-icons.css?_=' + Math.random(), $head);
                        $newCss('theme/tnc-template-content.css?_=' + Math.random(), $head);
                        log('css', self.css);
                        $newCss(self.css, $head);

                        self.applySettings();
                        self.loadLayers(reload);

                        if (callback) {
                            setTimeout(function() {
                                callback();
                            }, 1000);
                        }
                    }
                };

                setTimeout(function() {
                    self.$frameDoc = self.$frame.contents(); // .contentWindow.document

                    self.$frameDoc.ready(iframeReady);
                }, 50); // kleine timeout anders werkt het niet in firefox
            } else {
                self.applySettings();
                self.loadLayers(reload);
                if (callback) {
                    callback();
                }
            }
        };

        TncTemplate.prototype.loadLayers = function(reload) {
            var self = this;
            for (var i = 0; i < self.layers.length; i += 1) {
                var layer = self.layers[i];
                layer.load(self.$content, reload);
            }
        };

        TncTemplate.prototype.getPreloadTime = function() {
            var self = this;

            var preloadTime = 0;

            for (var i = 0; i < self.layers.length; i += 1) {
                var layer = self.layers[i];

                preloadTime = Math.max(layer.getPreloadTime(), preloadTime);
            }

            self.preloadTime = preloadTime;
            return preloadTime;
        };


        TncTemplate.prototype.applySettings = function() {
            var self = this;

            // Apply settings
            if (self.aspectRatioNumeric) {
                var ratio = self.aspectRatioNumeric;
                var css = {
                    'width': '100vw',
                    'height': (100 / ratio) + 'vw',
                    'max-height': '100vh',
                    'max-width': (100 * ratio) + 'vh'
                };
                self.$content.css(css);
            }

            self.$body.css('background-color', self.backgroundColor);
            if (self.backgroundImage !== '') {
                var folder = self.settings.folder || '';

                if (folder !== '') {
                    folder = folder + '/';
                }
                self.$body.css('background-image', 'url("' + resourceUrl(folder, self.backgroundImage) + '")');
                self.$body.css('background-size', 'cover');
            }
        };

        TncTemplate.prototype.getSettings = function() {
            var self = this;

            function getLayerSettings() {
                var layerSettings = [];
                var i;
                for (i = 0; i < self.layers.length; i += 1) {
                    layerSettings.push(self.layers[i].getSettings());
                }
                return layerSettings;
            }

            // Return (updated) settings from elements
            return {
                page: self.page,
                folder: self.folder,
                templateVersion: self.templateVersion,
                aspectRatio: self.aspectRatio,
                css: self.css,
                backgroundColor: self.backgroundColor,
                backgroundImage: self.backgroundImage,
                transition: self.transition.getSettings(),
                layers: getLayerSettings()
            };
        };

        TncTemplate.prototype.showTemplate = function() {
            var self = this;
            self.$panel.css({
                opacity: 1
            });
            self.$panel.show(0);
        };

        TncTemplate.prototype.hideTemplate = function() {
            var self = this;
            self.$panel.css({
                opacity: 0
            });
            self.$panel.hide(0);
        };

        TncTemplate.prototype.getDuration = function() {
            var self = this;

            var duration = 0;
            duration += 200; // reserved template load time
            duration += self.transition.duration;

            var i;
            for (i = 0; i < self.layers.length; i += 1) {
                duration += self.layers[i].getDuration();
            }

            return duration;
        };

        TncTemplate.prototype.pause = function() {
            var self = this;

            self.paused = true;
            var i;
            for (i = 0; i < self.layers.length; i += 1) {
                self.layers[i].pause();
            }
        };

        TncTemplate.prototype.beforePlay = function() {
            var self = this;
            var q = [];

            forEach(self.layers, function(layer) {
                q.push(layer.beforePlay());
            });

            return Promise.all(q)
                .then(function() {
                    self.scope.sendMessageCefhost('loadstatus', {
                        'ready': true,
                        id: self.id
                    });
                    log('loadstatus ready!');
                });
        };

        TncTemplate.prototype.play = function(resume) {
            var self = this;

            if (!self.isPlaying || (self.paused && resume)) {
                if (self.paused) {
                    log('playing resumed..');
                } else {
                    log('start playing..');
                }
                self.paused = false;
                self.isPlaying = true;
                self.stillPlaying = true;

                var layerPlayCount = self.layers.length;


                if (!self.durationExpired) {
                    setTimeout(function() {
                        // self.duration timeout reached
                        self.durationExpired = true;
                        log('>>> duration expired! <<<');

                        if (layerPlayCount <= 0 && self.durationExpired) {
                            log('>>> template ready! <<<');
                            self.isPlaying = false;
                            self.stillPlaying = false;
                            self.sendStillPlaying();
                            self.sendSocketReady();
                        }

                    }, self.duration);
                }

                self.onLayerReady = function(layer) {
                    layerPlayCount -= 1;
                    log('>>> layer ready: ' + layer.id);
                    if (layerPlayCount <= 0 && self.durationExpired) {
                        log('>>> template ready! <<<');
                        self.isPlaying = false;
                        self.stillPlaying = false;
                        self.sendStillPlaying();
                        self.sendSocketReady();

                        // test: repeat current template when ready
                        //window.location.href = window.location.href + '0';

                    } else if (layerPlayCount <= 0) {
                        log('>>> template ready, but template duration not expired');
                    }
                };

                forEach(self.layers, function(layer) {
                    layer.play(resume, function() {
                        self.onLayerReady(layer);
                    });
                });
            } else {
                log('error: already playing');
            }
        };

        TncTemplate.prototype.unload = function() {
            var self = this;

            for (var i = 0; i < self.layers.length; i += 1) {
                self.layers[i].unload();
            }
            delete self.layers;

            self.$element.remove();
            delete self.$element;

            if (self.$doc) {
                self.$doc.unbind();
                delete self.$doc;
            }

            if (self.$panel) {
                self.$panel.remove();
                delete self.$panel;
            }

            if (self.$frame) {
                self.$frame.remove();
                delete self.$frame;
            }

            if (self.$body) {
                self.$body.remove();
                delete self.$body;
            }

            if (self.$content) {
                self.$content.remove();
                delete self.$content;
            }

            if (self.$frameDoc) {
                self.$frameDoc.remove();
                delete self.$frameDoc;
            }

            del(self, 'margin');
            del(self, 'transition');

            delete self.onLayerReady;
            delete self.keyDownHandler;
            delete self.clickHandler;
            delete self.settings;
            delete self.css;
            delete self.aspectRatio;
            delete self.aspectRatioNumeric;
            delete self.backgroundColor;
            delete self.templateVersion;
            delete self.isPlaying;
            delete self.paused;

            self.unloaded = true;

            log('Template unloaded', self);
            self = null;
        };

        return TncTemplate;
    });
