function Slides(slides) {
    var self = this;
    self.values = {};
    self.slides = slides;
    self.language = 'en';

    _default_templates_url = 'templates.html';
    _default_stage = '#stage';
    _default_slide_template = '#slide-template';
    _default_button_template = '#button-template';
    _default_input_template = '#input-template';
    _default_choice_template = '#choice-template';

    templates_url = _default_templates_url;
    stage_template = _default_stage;
    slide_template = _default_slide_template;
    button_template = _default_button_template;
    input_template = _default_input_template;
    choice_template = _default_choice_template;

    function setupInputs(slide) {
        if(slide.inputs && _.isArray(slide.inputs)) {
            var formId = 'form-'+_.random(1, 1000);
            var form = $('<form id="'+formId+'"><input type="submit" class="hidden-submit"></form>');

            _.each(slide.inputs, function(input, i) {
                input.index = i;
                if(input.name && !input.id) {
                    input.id = input.name;
                } else {
                    input.id = input.index;
                }
                form.append(
                    self.inputTemplate({
                        'index': input.index,
                        'language': self.language,
                        'self': self,
                        'slide': slide,
                        'inputs': slide.inputs,
                        'input': input
                    })
                );
            });
            slide.formId = formId;
            slide.body = $('<p>').append(form).html();

            _.defer(function(){
                var pattern = /value-(.+)-(show|hide)/;
                _.each(slide.inputs, function(input, i) {
                    var funcs = _.filter(_.keys(input), function(k) {
                        return pattern.test(k)
                    });
                    _.each(funcs, function(fn) {
                        var m = pattern.exec(fn);
                        var name = m[1];
                        var action = m[2];
                        var func = input[fn];

                        var cc = '#slide-'+slide.id+'-'+input.id;
                        var cel = $(cc);

                        var val = self.values[name];
                        var args = [undefined, self, slide, slide.inputs, input, val];
                        switch(action) {
                            case 'show':
                                if(func.apply(this, args)) {
                                    cel.show();
                                } else {
                                    cel.hide();
                                }
                        }
                    });
                });
            });
        }
    }

    function setupEvents(slide) {
        // Events
        pattern = /on-(change|blur)-(.+)-(show|hide)/;
        if(slide.inputs && _.isArray(slide.inputs)) {
            _.each(slide.inputs, function (input, i) {
                var funcs = _.filter(_.keys(input), function(k) {
                    return pattern.test(k)
                });
                _.each(funcs, function(fn) {
                    var m = pattern.exec(fn);
                    var event = m[1];
                    var name = m[2];
                    var action = m[3];
                    var func = input[fn]

                    $('[name='+name+']').on(event, function(e) {
                        var cc, cel;

                        if(_.includes(['checkbox', 'radio'], input.type)) {
                            cc = '[name='+input.name+']';
                            cel = $($(cc)[0]).closest('.slide-input');
                        } else {
                            cc = '#slide-'+slide.id+'-'+input.id;
                            cel = $(cc).closest('.slide-input');
                        }

                        var s = $(slide.form).serializeArray();
                        var val = _.filter(s, function(f) {
                            return f.name == name
                        }).map(function(f){ return f.value });
                        var args = [e, self, slide, slide.inputs, input, val];
                        switch(action) {
                            case 'show':
                                if(func.apply(this, args)) {
                                    cel.show();

                                    if(input.required && input.required == true || !input.hasOwnProperty('required')) {
                                        cel.find('[required]:not(.required)').attr('required', true)

                                        if(!_.includes(['checkbox', 'radio'], input.type)) {
                                            cel.find('[name]').attr('required', true);
                                        }
                                    }
                                } else {
                                    cel.hide();

                                    if(input.required && input.required == true || !input.hasOwnProperty('required')) {
                                        cel.find('[required]:not(.required)').attr('required', null)
                                    }
                                }
                        }
                    });
                })
            });
        }

        _.each(slide.inputs, function(input) {
            if(_.includes(['checkbox', 'radio'], input.type) &&
                (input.required && input.required == true || !input.hasOwnProperty('required'))
            ) {
                $('[name='+input.name+']').on('change', function(){
                    var s = $(slide.form).serializeArray();
                    var val = _.filter(s, function(f) {
                        return f.name == input.name
                    }).map(function(f){ return f.value });

                    if(_.size(val) > 0) {
                        $('[name='+input.name+'_required]').val(true)
                    } else {
                        $('[name='+input.name+'_required]').val('')
                    }

                });
            }
        })
    }

    function setupButtons(slide) {
        if(slide.buttons && slide.buttons.length > 0) {
            _.each(slide.buttons, function(button, i) {
                if(!button.id) {
                    button.id = i;
                }
                if(button.type) {
                    var gt = /^go-to(.+)$/;

                    if(button.type == 'next') {
                        $('#'+slide.id+'-button-'+button.id).click(function(e){
                            console.log('Next');
                            $('#'+slide.formId+' input[type=submit]').click();
                        });
                        $('#'+slide.formId).on('submit', function(e){
                            console.log('Submitted!');
                            self.saveSlideById(slide.id);
                            self.renderSlide(getNextSlide(slide));
                            e.preventDefault();
                            return false;
                        });
                    } else if(button.type == 'prev') {
                        $('#'+slide.id+'-button-'+button.id).click(function(e){
                            console.log('Previous');
                            self.saveSlideById(slide.id);
                            self.renderSlide(getPrevSlide(slide))
                        });
                    } else if(button.type == 'submit') {
                        $('#'+slide.id+'-button-'+button.id).click(function(e){
                            console.log('Submit');
                            $('#'+slide.formId+' input[type=submit]').click();
                        });
                        $('#'+slide.formId).on('submit', function(e) {
                            console.log('Submitted!');
                            self.saveSlideById(slide.id);
                            button.click(e, self, slide, button);
                            e.preventDefault();
                            return false;
                        });
                    } else if(gt.test(button.type)) {
                        $('#'+slide.id+'-button-'+button.id).click(function(e){
                            self.saveSlideById(slide.id);
                            var m = gt.exec(button.type);
                            if(m && m[1]) {
                                self.renderSlide(self.getSlideById(m[1]))
                            }
                        });
                    }
                }
                if(button.type != 'submit' && button.click) {
                    $('#'+slide.id+'-button-'+button.id).click(function(e){
                        button.click(e, self, slide, button)
                    });
                }
            })
        }
    }

    function renderSlide(slide) {
        var index = _.findIndex(self.slides, slide);
        console.log(index);
        slide.index = index;
        setupInputs(slide);

        self.stage.html(self.stageTemplate({
            'language': self.language,
            'self': self,
            'slide': slide
        })).addClass('slide stage');
        slide.form = $('#'+slide.formId);

        setupButtons(slide);
        setupEvents(slide);
        $('input:not(.invisible)').trigger('change').trigger('blur');
        $('[required]:not(.required)').addClass('required-input');
    }

    function getSlideByIndex(index) {
        return self.slides[index]
    }

    function getNextSlide(slide) {
        if(self.slides.length > slide.index) {
            return getSlideByIndex(slide.index+1)
        }
        return null;
    }

    function getPrevSlide(slide) {
        if(slide.index > 0) {
            return getSlideByIndex(slide.index-1)
        }
        return null;
    }

    function getSlideById(id) {
        return _.first(_.filter(self.slides, function(s){return s.id==id}))
    }

    function saveSlideById(id) {
        var slide = getSlideById(id);
        var data = $(slide.form).serializeArray();
        _.each(slide.inputs, function(input) {
            if(input.name) {
                var vals = _.filter(data, function(d) { return d.name == input.name });
                if(_.size(vals) > 0) {
                    vals = _.map(vals, 'value');
                    if(_.includes(['select', 'radio', 'checkbox'], input.type)) {
                        _.each(input.choices, function(choice) {
                            choice.selected = _.includes(vals, choice.value);
                        });
                        self.values[input.name] = vals;
                    } else {
                        input.value = _.head(vals);
                        self.values[input.name] = input.value;
                    }
                }
            }
        });
        console.log(data);
    }

    function render(slide) {
        self.stage = $(stage_template);
        self.stageTemplate = _.template($(slide_template).html());
        self.inputTemplate = _.template($(input_template).html());
        self.buttonTemplate = _.template($(button_template).html());
        self.choiceTemplate = _.template($(choice_template).html());

        if(!slide) {
            slide = _.head(self.slides);
        }

        self.renderSlide(slide)
    }

    function getTemplates(url, fn) {
        turl = url || templates_url;
        $.get(turl, function(r) {
            $('html').append(r);

            if(fn) {
                fn()
            } else {
                render()
            }
        });
    }

    function finalSubmit(fn) {
        self._finalSubmit = fn;
    }

    function invokeFinalSubmit() {
        if(self._finalSubmit) {
            self._finalSubmit(self.values);
        }
    }

    self.getSlideById = getSlideById;
    self.renderSlide = renderSlide;
    self.saveSlideById = saveSlideById;
    self.render = render;
    self.getTemplates = getTemplates;
    self.getNextSlide = getNextSlide;
    self.getPrevSlide = getPrevSlide;
    self.finalSubmit = finalSubmit;
    self.invokeFinalSubmit = invokeFinalSubmit;

    //getTemplates();
}
