(function () {
    'use strict';

// raise an error in test mode if openerp don't exist
if (typeof openerp === "undefined") {
    var error = "openerp is undefined"
                + "\nhref: " + window.location.href
                + "\nreferrer: " + document.referrer
                + "\nlocalStorage: " + JSON.stringify(window.localStorage);
    if (typeof $ !== "undefined") {
        error += '\n\n' + $("body").html();
    }
    throw new Error(error);
}

var website = window.openerp.website;

// don't rewrite website.Tour in test mode
if (typeof website.Tour !== "undefined") {
    return;
}

// don't need template to use bootstrap Tour in automatic mode
if (typeof QWeb2 !== "undefined") {
    website.add_template_file('/website/static/src/xml/website.tour.xml');

}

// don't need to use bootstrap Tour to launch an automatic tour
function bootstrap_tour_stub () {
    if (typeof Tour === "undefined") {
        window.Tour = function Tour() {};
        Tour.prototype.addSteps = function () {};
        Tour.prototype.end = function () {};
        Tour.prototype.goto = function () {};
    }
}



if (website.EditorBar) {
    website.EditorBar.include({
        tours: [],
        start: function () {
            var self = this;
            var menu = $('#help-menu');
            _.each(this.tours, function (tour) {
                var $menuItem = $($.parseHTML('<li><a href="#">'+tour.name+'</a></li>'));
                $menuItem.click(function () {
                    tour.reset();
                    tour.run();
                });
                menu.append($menuItem);
            });
            return this._super();
        },
        registerTour: function (tour) {
            website.Tour.add(tour);
            this.tours.push(tour);
        }
    });
}


/////////////////////////////////////////////////


/* jQuery selector to match exact text inside an element
 *  :containsExact()     - case insensitive
 *  :containsExactCase() - case sensitive
 *  :containsRegex()     - set by user ( use: $(el).find(':containsRegex(/(red|blue|yellow)/gi)') )
 */
$.extend($.expr[':'],{
    containsExact: function(a,i,m){
        return $.trim(a.innerHTML.toLowerCase()) === m[3].toLowerCase();
    },
    containsExactCase: function(a,i,m){
        return $.trim(a.innerHTML) === m[3];
    },
    // Note all escaped characters need to be double escaped
    // inside of the containsRegex, so "\(" needs to be "\\("
    containsRegex: function(a,i,m){
        var regreg =  /^\/((?:\\\/|[^\/])+)\/([mig]{0,3})$/,
        reg = regreg.exec(m[3]);
        return reg ? new RegExp(reg[1], reg[2]).test($.trim(a.innerHTML)) : false;
    }
});
$.ajaxSetup({
    beforeSend:function(){
        $.ajaxBusy = ($.ajaxBusy|0) + 1;
    },
    complete:function(){
        $.ajaxBusy--;
    }
});

website.Tour = openerp.Class.extend({
    steps: [],
    defaultDelay: 50, //ms
    defaultOverLaps: 5000, //ms
    localStorage: window.localStorage,
    init: function () {},

    run: function (automatic) {
        this.reset();

        for (var k in this.localStorage) {
            if (!k.indexOf("tour-") && k.indexOf("-test") > -1) return;
        }

        website.Tour.busy = true;

        if (automatic) {
            this.localStorage.setItem("tour-"+this.id+"-test-automatic", true);
        } else {
            this.localStorage.removeItem("tour-"+this.id+"-test-automatic");
        }
        this.automatic = automatic;

        if (this.path) {
            // redirect to begin of the tour in function of the language
            if (!this.testUrl(this.path+"(#.*)?$")) {
                var path = this.path.split('#');
                window.location.href = "/"+this.getLang()+path[0] + "#tutorial."+this.id+"=true&" + path.slice(1, path.length).join("#");
                return;
            }
        }

        var self = this;
        this.localStorage.setItem("tour-"+this.id+"-test", 0);
        website.Tour.waitReady.call(this, function () {self._running();});
    },
    running: function () {
        var self = this;
        if (+this.localStorage.getItem("tour-"+this.id+"-test") >= this.steps.length-1) {
            this.endTour();
            return;
        }

        if (website.Tour.is_busy()) return;

        // launch tour with url
        this.checkRunningUrl();

        // mark tour as busy (only one test running)
        if (this.localStorage.getItem("tour-"+this.id+"-test") != null) {
            website.Tour.busy = true;
            this.automatic = !!this.localStorage.getItem("tour-"+this.id+"-test-automatic");
        }

        if (!this.testPathUrl()) {
            if (this.automatic) {
                this.timer = setTimeout(function () {
                    self.reset();
                    throw new Error("Wrong url for running " + self.id
                        + '\ntestPath: ' + self.testPath
                        + '\nhref: ' + window.location.href
                        + "\nreferrer: " + document.referrer
                    );
                },this.defaultOverLaps);
            }
            return;
        }

        var self = this;
        website.Tour.waitReady.call(this, function () {self._running();});
    },
    _running: function () {
        var stepId = this.localStorage.getItem("tour-"+this.id+"-test");

        if (stepId != null) {
            this.registerTour();
            this.nextStep(stepId,  this.automatic ? this.autoNextStep : null, this.automatic ? this.defaultOverLaps : null);
        }
    },

    reset: function () {
        website.Tour.busy = false;
        for (var k in this.steps) {
            this.steps[k].busy = false;
        }
        clearTimeout(self.timer);
        clearTimeout(self.testtimer);

        for (var k in this.localStorage) {
            if (!k.indexOf("tour-") || !k.indexOf(this.id)) {
                this.localStorage.removeItem(k);
            }
        }

        $('.popover.tour').remove();
    },

    getLang: function () {
        return $("html").attr("lang").replace(/-/, '_');
    },
    testUrl: function (url) {
        return new RegExp("(/"+this.getLang()+")?"+url, "i").test(window.location.href);
    },
    testPathUrl: function () {
        if (!this.testPath || this.testUrl(this.testPath)) return true;
    },
    checkRunningUrl: function () {
        if (window.location.hash.indexOf("tutorial."+this.id+"=true") > -1) {
            this.localStorage.setItem("tour-"+this.id+"-test", 0);
            window.location.hash = window.location.hash.replace(/tutorial.+=true&?/, '');
        }
    },

    registerTour: function () {
        if (this.automatic) {
            bootstrap_tour_stub();
        }
        this.tour = new Tour({
            name: this.id,
            storage: this.tourStorage,
            keyboard: false,
            template: this.popover(),
            onHide: function () {
                window.scrollTo(0, 0);
            }
        });
        this.registerSteps();
    },
    registerSteps: function () {
        for (var index=0, len=this.steps.length; index<len; index++) {
            var step = this.steps[index];
            step.stepId = step.stepId || ""+index;

            if (!step.waitNot && index > 0 && this.steps[index-1] &&
                this.steps[index-1].popover && this.steps[index-1].popover.next) {
                step.waitNot = '.popover.tour:visible';
            }
            if (!step.waitFor && index > 0 && this.steps[index-1].snippet) {
                step.waitFor = '.oe_overlay_options .oe_options:visible';
            }

            step._title = step._title || step.title;
            step.title = this.popoverTitle({ title: step._title });
            step.template = step.template || this.popover( step.popover );

            if (!step.element) step.orphan = true;
            if (step.snippet) {
                step.element = '#oe_snippets '+step.snippet+' .oe_snippet_thumbnail';
            }

        }

        if (this.steps[index-1] &&
            this.steps[index-1].popover && this.steps[index-1].popover.next) {
            var step = {
                stepId:    ""+index,
                waitNot:   '.popover.tour:visible'
            };
            this.steps.push(step);
        }

        this.tour.addSteps(this.steps);
    },

    popoverTitle: function (options) {
        try {
            return openerp.qweb.render('website.tour_popover_title', options);
        } catch (e) {
            if (!this.automatic) throw e;
            return options.title;
        }
    },
    popover: function (options) {
        try {
            return openerp.qweb.render('website.tour_popover', options);
        } catch (e) {
            if (!this.automatic) throw e;
            return "";
        }
    },

    timer: null,
    testtimer: null,
    check: function (step) {
        return (step &&
            (!step.element || ($(step.element).size() && $(step.element).is(":visible") && !$(step.element).is(":hidden"))) &&
            (!step.waitNot || !$(step.waitNot).size()) &&
            (!step.waitFor || $(step.waitFor).size()));
    },
    waitNextStep: function (step, callback, overlaps) {
        var self = this;
        var time = new Date().getTime();
        var timer;

        window.onbeforeunload = function () {
            clearTimeout(self.timer);
            clearTimeout(self.testtimer);
        };

        // check popover activity
        $(".popover.tour button")
            .off()
            .on("click", function () {
                $(".popover.tour").remove();
                if (step.busy) return;
                if (!$(this).is("[data-role='next']")) {
                    clearTimeout(self.timer);
                    step.busy = true;
                    self.tour.end();
                    self.endTour(callback);
                }
            });

        function checkNext () {
            clearTimeout(self.timer);
            if (step.busy) return;
            if (self.check(step)) {
                step.busy = true;
                // use an other timeout for cke dom loading
                setTimeout(function () {
                    self.nextStep(step.stepId, callback, overlaps);
                }, self.defaultDelay);
            } else if (!overlaps || new Date().getTime() - time < overlaps) {
                if (self.current.element) {
                    var $popover = $(".popover.tour");
                    if(!$(self.current.element).is(":visible")) {
                        $popover.data("hide", true).fadeOut(300);
                    } else if($popover.data("hide")) {
                        $popover.data("hide", false).fadeIn(150);
                    }
                }
                self.timer = setTimeout(checkNext, self.defaultDelay);
            } else {
                self.reset();
                throw new Error("Can't arrive to step " + step.stepId + ": '" + step._title + "'"
                    + '\nhref: ' + window.location.href
                    + '\nelement: ' + Boolean(!step.element || ($(step.element).size() && $(step.element).is(":visible") && !$(step.element).is(":hidden")))
                    + '\nwaitNot: ' + Boolean(!step.waitNot || !$(step.waitNot).size())
                    + '\nwaitFor: ' + Boolean(!step.waitFor || $(step.waitFor).size())
                    + '\n\n' + $("body").html()
                );
            }
        }
        checkNext();
    },
    step: function (stepId) {
        var steps = this.steps.slice(0,this.steps.length),
            step;
        while (step = steps.shift()) {
            if (!stepId || step.stepId === stepId)
                return step;
        }
        return null;
    },
    next: function (stepId) {
        var steps = this.steps.slice(0,this.steps.length),
            step, next, index=0;
        while (step = steps.shift()) {
            if (!stepId || step.stepId === stepId) {
                // clear popover (fix for boostrap tour if the element is removed before destroy popover)
                $(".popover.tour").remove();
                // go to step in bootstrap tour
                this.tour.goto(index);
                if (step.onload) step.onload();
                next = steps.shift();
                break;
            }
            index++;
        }
        return next;
    },
    nextStep: function (stepId, callback, overlaps) {
        var self = this;
        if (!this.localStorage.getItem("tour-"+this.id+"-test")) return;

        this.localStorage.setItem("tour-"+this.id+"-test", stepId || 0);

        this.current = this.step(stepId);
        var next = this.next(stepId);

        if (next) {
            setTimeout(function () {
                    self.waitNextStep(next, callback, overlaps);
                    if (callback) setTimeout(function(){callback.call(self, next);}, self.defaultDelay);
            }, next && next.wait || 0);
        } else {
            this.endTour();
        }
    },
    endTour: function () {
        var test = parseInt(this.localStorage.getItem("tour-"+this.id+"-test"),10) >= this.steps.length-1;
        this.reset();
        if (test) {
            console.log('ok');
        } else {
            console.log('error');
        }
    },
    autoNextStep: function () {
        var self = this;
        clearTimeout(self.testtimer);

        function autoStep () {
            var step = self.current;
            if (!step) return;

            if (step.autoComplete) {
                step.autoComplete(tour);
            }

            var $popover = $(".popover.tour");
            if ($popover.find("button[data-role='next']:visible").size()) {
                $popover.find("button[data-role='next']:visible").click();
                $popover.remove();
            }

            var $element = $(step.element);
            if (!$element.size()) return;

            if (step.snippet) {
            
                var selector = '#oe_snippets '+step.snippet+' .oe_snippet_thumbnail';
                self.autoDragAndDropSnippet(selector);
            
            } else if (step.element.match(/#oe_snippets .* \.oe_snippet_thumbnail/)) {
            
                self.autoDragAndDropSnippet($element);
            
            } else if (step.sampleText) {
            
                $element.trigger($.Event("keydown", { srcElement: $element }));
                if ($element.is("input") ) {
                    $element.val(step.sampleText);
                } if ($element.is("select")) {
                    $element.find("[value='"+step.sampleText+"'], option:contains('"+step.sampleText+"')").attr("selected", true);
                    $element.val(step.sampleText);
                } else {
                    $element.html(step.sampleText);
                }
                setTimeout(function () {
                    $element.trigger($.Event("keyup", { srcElement: $element }));
                    $element.trigger($.Event("change", { srcElement: $element }));
                }, self.defaultDelay<<1);
            
            } else if ($element.is(":visible")) {

                $element.trigger($.Event("mouseenter", { srcElement: $element[0] }));
                $element.trigger($.Event("mousedown", { srcElement: $element[0] }));
        
                var evt = document.createEvent("MouseEvents");
                evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                $element[0].dispatchEvent(evt);

                // trigger after for step like: mouseenter, next step click on button display with mouseenter
                setTimeout(function () {
                    $element.trigger($.Event("mouseup", { srcElement: $element[0] }));
                    $element.trigger($.Event("mouseleave", { srcElement: $element[0] }));
                }, 1000);
            }
        }
        self.testtimer = setTimeout(autoStep, 100);
    },
    autoDragAndDropSnippet: function (selector) {
        var $thumbnail = $(selector).first();
        var thumbnailPosition = $thumbnail.position();
        $thumbnail.trigger($.Event("mousedown", { which: 1, pageX: thumbnailPosition.left, pageY: thumbnailPosition.top }));
        $thumbnail.trigger($.Event("mousemove", { which: 1, pageX: document.body.scrollWidth/2, pageY: document.body.scrollHeight/2 }));
        var $dropZone = $(".oe_drop_zone").first();
        var dropPosition = $dropZone.position();
        $dropZone.trigger($.Event("mouseup", { which: 1, pageX: dropPosition.left, pageY: dropPosition.top }));
    },

});


website.Tour.tours = {};
website.Tour.busy = false;
website.Tour.add = function (tour) {
    website.Tour.waitReady(function () {
        tour = tour.id ? tour : new tour();
        if (!website.Tour.tours[tour.id]) {
            website.Tour.tours[tour.id] = tour;
            tour.running();
        }
    });
};
website.Tour.get = function (id) {
    return website.Tour.tours[id];
};
website.Tour.each = function (callback) {
    website.Tour.waitReady(function () {
        for (var k in website.Tour.tours) {
            callback.call(website.Tour.tours[k]);
        }
    });
};
website.Tour.waitReady = function (callback) {
    var self = this;
    $(document).ready(function () {
        if ($.ajaxBusy) {
            $(document).ajaxStop(function() {
                setTimeout(function () {
                    callback.call(self);
                },0);
            });
        }
        else {
            setTimeout(function () {
                callback.call(self);
            },0);
        }
    });
};
website.Tour.run_test = function (id) {
    website.Tour.waitReady(function () {
        if (!website.Tour.is_busy()) {
            website.Tour.tours[id].run(true);
        }
    });
};
website.Tour.is_busy = function () {
    for (var k in this.localStorage) {
        if (!k.indexOf("tour-")) {
            return k;
        }
    }
    return website.Tour.busy;
};


}());
