define(['jquery', 'tools/tools', 'tools/validate', 'tools/tools-3d', 'TweenMax.min', 'bluebird'], function () {
    'use strict';
    // var $ = require('jquery');
    var tools = require('tools/tools');
    var validate = require('tools/validate');
    var tools3d = require('tools/tools-3d');
    var Promise = require('bluebird');

    var numbers = require('tools/numbers');
    var round100 = numbers.round100;

    // var log = tools.log;
    //var format = tools.format;

    var getStr = validate.getStr;
    var getNum = validate.getNum;
    //var getColor = validate.getColor;
    var limitOpacity = tools.limitOpacity;
    var del = tools.del;

    var w = window;

    var setTimeout = w.setTimeout;

    // Global tween variables
    var TweenLite = w.TweenLite,
        TweenMax = w.TweenMax,
        TimelineMax = w.TimelineMax,
        Sine = w.Sine;

    //    var x64 = false;
    //
    //    if (w.navigator.userAgent.indexOf("WOW64") != -1 ||
    //        w.navigator.userAgent.indexOf("Win64") != -1 ){
    //       x64 = true;
    //    } else {
    //       x64 = false;
    //    }

    // To turn on/off RequestAnimationFrame:
    TweenLite.ticker.useRAF(true);

    //if (!x64) {
    // throttle back the frames-per-second to 25
    TweenLite.ticker.fps(30);
    //}

    // reduce lagSmoothing
    TweenLite.lagSmoothing(500, 33);

    // =======
    // Transition
    function TncTransition(settings) {
        this.init(settings);
    }

    TncTransition.prototype.transitionsDisabled = false;

    TncTransition.prototype.init = function (settings) {
        var self = this;
        self.settings = settings || {};
        self.transitionType = getStr(self.settings.transitionType, 'fade').toLowerCase();
        self.duration = getNum(self.settings.duration, 2000);
        self.delay = getNum(self.settings.delay, 0);
        self.extraDelay = 0; // For custom situations
        self.transitionDisabled = false;
    };

    TncTransition.prototype.run = function ($e_new, $e_old) {
        var self = this;
        return new Promise(function (resolve, reject) {
            var ready = function () {
                resolve();
            };
            self.applyTransition(null, null, $e_new, $e_old, ready);
        });
    };

    TncTransition.prototype.applyTransition = function (obj_new, obj_old, $e_new, $e_old, callback) {
        var self = this;

        // if (self.delay > 0)
        // {
        var duration = self.duration;
        if (self.transitionDisabled) {
            duration = 0;
        }

        if (TncTransition.prototype.transitionsDisabled) {
            duration = 0;
        }

        var transitionCallback = function () {
            setTimeout(callback, 50);
        };

        switch (self.transitionType) {
            case 'rotate3d-top':
                self.rotate3d_top($e_new, $e_old, duration, transitionCallback);
                break;
            case 'rotate3d-bottom':
                self.rotate3d_bottom($e_new, $e_old, duration, transitionCallback);
                break;
            case 'rotate3d-right':
                self.rotate3d_right($e_new, $e_old, duration, transitionCallback);
                break;
            case 'rotate3d-left':
                self.rotate3d_left($e_new, $e_old, duration, transitionCallback);
                break;
            case 'scale':
                self.scale($e_new, $e_old, duration, transitionCallback);
                break;
            case 'clips':
                self.clips($e_new, $e_old, duration, transitionCallback);
                break;
            case 'none':
                {
                    duration = 0;
                    self.fade_in($e_new, $e_old, duration, transitionCallback);
                    break;
                }
            case 'fadein':
                self.fade_in($e_new, $e_old, duration, transitionCallback);
                break;
            default:
                self.fade_in($e_new, $e_old, duration, transitionCallback);
        }
    };

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

        return {
            transitionType: self.transitionType,
            duration: self.duration
        };
    };

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

        del(self, 'settings');
        //self.obj = null;

        self.unloaded = true;

        //log('Transition unloaded', self);
        self = null;
    };

    var addtimeLineAnimation = function (tl, s) {
        if (s.set) {
            TweenMax.set(s.$e, s.set);
        }
        if (s.from) {
            tl.insert(TweenMax.fromTo(s.$e, s.duration / 1000, s.from, s.to), 0.2);
        } else {
            tl.insert(TweenMax.to(s.$e, s.duration / 1000, s.to), 0.2);
        }
    };

    var timeLineAnimate = function (anims, callback) {
        var tl = new TimelineMax({
            immediateRender: false,
            onComplete: function () {
                tl.kill();
                tl = null;
                setTimeout(function () {
                    callback();
                }, 0);
            }
        });
        var i;
        for (i = 0; i < anims.length; i++) {
            addtimeLineAnimation(tl, anims[i]);
        }
        tl.pause();
        setTimeout(function () {
            if (tl) {
                tl.play();
            }
        }, 100);
    };

    // TRANSITION TYPES

    TncTransition.prototype.rotate3Dhelper = function ($e_new, $e_old, duration, property, reverse, callback) {
        var vertical = (property == 'rotationX');
        var radius = tools3d.getRadius($e_new, 4, vertical);
        var origin = '50% 50% ' + (-round100(radius)) + 'px';

        var degFrom = 90;
        var degTo = -90;

        if (reverse) {
            degFrom = degFrom * -1;
            degTo = degTo * -1;
        }

        var anims = [];
        var anim = null;
        if ($e_new) {
            $e_new.parent().css('transformStyle', 'preserve-3d');
            anim = {
                $e: $e_new,
                duration: duration,
                set: {
                    transformPerspective: 1000,
                    transformOrigin: origin,
                    '-webkit-backface-visibility': 'hidden',
                    backfaceVisibility: 'hidden',
                    opacity: limitOpacity(1),
                    transition: 'none',
                    zIndex: 10
                },
                to: {
                    zIndex: 30,
                    ease: Sine.easeOut
                }
            };
            anim.set[property] = degFrom; //.from[property]
            anim.to[property] = 0;
            anims.push(anim);
        }
        if ($e_old) {
            anim = {
                $e: $e_old,
                duration: duration,
                set: {
                    transformPerspective: 1000,
                    transformOrigin: origin,
                    '-webkit-backface-visibility': 'hidden',
                    backfaceVisibility: 'hidden',
                    transition: 'none',
                    opacity: limitOpacity(1),
                    zIndex: 20
                },
                to: {
                    ease: Sine.easeOut
                }
            };
            anim.set[property] = 0; //.from[property]
            anim.to[property] = degTo;
            anims.push(anim);
        }

        timeLineAnimate(anims, callback);
    };

    TncTransition.prototype.fade_in = function ($e_new, $e_old, duration, callback) {
        var self = this;
        var anims = [];
        var anim = null;
        if ($e_new) {
            anim = {
                $e: $e_new,
                duration: duration,
                set: {
                    opacity: limitOpacity(0),
                    zIndex: 20
                },
                to: {
                    opacity: limitOpacity(1),
                    ease: Sine.easeOut
                }
            };
            anims.push(anim);
        }
        if ($e_old) {
            anim = {
                $e: $e_old,
                duration: duration,
                set: {
                    opacity: limitOpacity(1),
                    zIndex: 5
                },
                to: {
                    opacity: limitOpacity(0),
                    ease: Sine.easeOut
                }
            };
            anims.push(anim);
        }

        timeLineAnimate(anims, callback);
    };

    TncTransition.prototype.scale = function ($e_new, $e_old, duration, callback) {
        var self = this;
        var anims = [];
        var anim = null;

        if ($e_new) {
            anim = {
                $e: $e_new,
                duration: duration,
                set: {
                    opacity: limitOpacity(0),
                    scale: 0.1,
                    zIndex: 20
                },
                to: {
                    opacity: limitOpacity(1),
                    scale: 1,
                    ease: Sine.easeOut
                }
            };
            anims.push(anim);
        }
        if ($e_old) {
            anim = {
                $e: $e_old,
                duration: duration,
                set: {
                    opacity: limitOpacity(1),
                    zIndex: 5
                },
                to: {
                    opacity: limitOpacity(0),
                    ease: Sine.easeOut
                }
            };
            anims.push(anim);
        }
        timeLineAnimate(anims, callback);
    };

    TncTransition.prototype.rotate3d_left = function ($e_new, $e_old, duration, callback) {
        var self = this;

        self.rotate3Dhelper($e_new, $e_old, duration, 'rotationY', false, callback);
    };

    TncTransition.prototype.rotate3d_right = function ($e_new, $e_old, duration, callback) {
        var self = this;
        self.rotate3Dhelper($e_new, $e_old, duration, 'rotationY', true, callback);
    };

    TncTransition.prototype.rotate3d_top = function ($e_new, $e_old, duration, callback) {
        var self = this;
        self.rotate3Dhelper($e_new, $e_old, duration, 'rotationX', false, callback);
    };

    TncTransition.prototype.rotate3d_bottom = function ($e_new, $e_old, duration, callback) {
        var self = this;

        self.rotate3Dhelper($e_new, $e_old, duration, 'rotationX', true, callback);
    };


    return TncTransition;
});
