define(['jquery', 'underscore', 'requtils', 'renderer/baserepresentation'], function ($, _, requtils, BaseRepresentation) {
    'use strict';

    var Utils = requtils.getUtils();

    /* Rkns.Renderer.View Class */

    /* The representation for the view. */

    var ViewRepr = Utils.inherit(BaseRepresentation);

    _(ViewRepr.prototype).extend({
        _init: function() {
            var _this = this;
            this.$ = $(".Rk-Render");
            this.type = "View";
            this.hiddenNodes = [];
            this.scale = 1;
            this.initialScale = 1;
            this.offset = paper.view.center;
            this.params = {};
            
            if (this.model){
                this.params = {
                    "zoom_level": _this.model.get("zoom_level"),
                    "offset": _this.model.get("offset"),
                    "hidden_nodes": _this.model.get("hidden_nodes")
                };
            }
                
            this.initWithParams();
            
            var bindClick = function(selector, fname) {
                _this.$.find(selector).click(function(evt) {
                    _this[fname](evt);
                    return false;
                });
            };
            
            bindClick(".Rk-ZoomOut", "zoomOut");
            bindClick(".Rk-ZoomIn", "zoomIn");
            bindClick(".Rk-ZoomFit", "autoScale");
            bindClick(".Rk-ZoomSave", "saveView");
            
            this.$.find(".Rk-ZoomSetSaved").click( function() {
                _this.setScale(_this.params.zoom_level, new paper.Point(_this.params.offset));
                _this.showNodes(false);
                if (_this.options.hide_nodes){
                    _this.hiddenNodes = (_this.params.hidden_nodes || []).concat();
                    _this.hideNodes();
                }
                _this.updateUrl();
            });
            
            this.$.find(".Rk-ShowHiddenNodes").mouseenter( function() {
                _this.showNodes(true);
                _this.$.find(".Rk-ShowHiddenNodes").mouseleave( function() {
                    _this.hideNodes();
                });
            });
            this.$.find(".Rk-ShowHiddenNodes").click( function() {
                _this.showNodes(false);
                _this.$.find(".Rk-ShowHiddenNodes").off( "mouseleave" ); 
            });
            
            if(this.renkan.project.get("views").length > 0 && this.renkan.options.save_view){
                this.$.find(".Rk-ZoomSetSaved").show();
            }
        },
        redraw: function(options) {
            //console.log("view : ", this.model.toJSON());
        },
        initWithParams: function(){
            var _this = this;
            
            if (_this.options.view_force_autoscale){
                this.autoScale();
            } else {
                _this.setScale(_this.params.zoom_level, new paper.Point(_this.params.offset));                
            }
            
            if (_this.options.hide_nodes && !_this.options.view_show_hiddennodes){
                _this.hiddenNodes = (_this.params.hidden_nodes || []).concat();
                _this.hideNodes();
            } else {
                _this.showNodes(false);
            }
        },
        saveView: function(){
            var _this = this;
            
            var offset = {
                "x": _this.offset.x,
                "y": _this.offset.y
            };
            
            _this.model = _this.renkan.project.addView( { zoom_level:_this.scale, offset:offset, hidden_nodes: _this.hiddenNodes.concat() } );
            _this.params = {
                    "zoom_level": _this.model.get("zoom_level"),
                    "offset": _this.model.get("offset"),
                    "hidden_nodes": _this.model.get("hidden_nodes")
            };
            
            this.$.find(".Rk-ZoomSetSaved").show();
            
            _this.updateUrl();
        },
        addHiddenNode: function(_model){
            this.hideNode(_model);
            this.hiddenNodes.push(_model.id);
            this.updateUrl();
        },
        hideNode: function(_model){
            if (typeof this.renderer.getRepresentationByModel(_model) !== 'undefined'){
                this.renderer.getRepresentationByModel(_model).hide();
            }
        },
        hideNodes: function(){
            var _this = this;
            this.hiddenNodes.forEach(function(_id, index){
                var node = _this.renkan.project.get("nodes").get(_id);
                if (typeof node !== 'undefined'){
                    return _this.hideNode(_this.renkan.project.get("nodes").get(_id));
                }else{
                    _this.hiddenNodes.splice(index, 1);
                }
            });
            paper.view.draw();
        },
        showNodes: function(ghost){
            var _this = this;
            this.hiddenNodes.forEach(function(_id){
                _this.renderer.getRepresentationByModel(_this.renkan.project.get("nodes").get(_id)).show(ghost);
            });
            if (!ghost){
                this.hiddenNodes = [];
            }
            paper.view.draw();
        },
        setScale: function(_newScale, _offset) {
            if ((_newScale/this.initialScale) > Utils._MIN_SCALE && (_newScale/this.initialScale) < Utils._MAX_SCALE) {
                this.scale = _newScale;
                if (_offset) {
                    this.offset = _offset;
                }
                this.renderer.redraw();
                this.updateUrl();
            }
        },
        zoomOut: function() {
            var _newScale = this.scale * Math.SQRT1_2,
            _offset = new paper.Point([
                                       this.renderer.canvas_$.width(),
                                       this.renderer.canvas_$.height()
                                       ]).multiply( 0.5 * ( 1 - Math.SQRT1_2 ) ).add(this.offset.multiply( Math.SQRT1_2 ));
            this.setScale( _newScale, _offset );
        },
        zoomIn: function() {
            var _newScale = this.scale * Math.SQRT2,
            _offset = new paper.Point([
                                       this.renderer.canvas_$.width(),
                                       this.renderer.canvas_$.height()
                                       ]).multiply( 0.5 * ( 1 - Math.SQRT2 ) ).add(this.offset.multiply( Math.SQRT2 ));
            this.setScale( _newScale, _offset );
        },
        resizeZoom: function(deltaW, deltaH, _ratio) {
            var _newScale = this.scale * _ratio;
            var _offset = new paper.Point([
                                       (this.renderer.canvas_$.width() * 0.5 * ( 1 - _ratio) ) + (this.offset.x * _ratio + deltaW * _ratio * 0.5 ),
                                       (this.renderer.canvas_$.height() * 0.5 * ( 1 - _ratio) ) + (this.offset.y * _ratio + deltaH * _ratio * 0.5 )
                                       ]);
            this.setScale( _newScale, _offset );
        },
        autoScale: function(force_view) {
            var nodes = this.renkan.project.get("nodes");
            if (nodes.length > 1) {
                var _xx = nodes.map(function(_node) { return _node.get("position").x; }),
                _yy = nodes.map(function(_node) { return _node.get("position").y; }),
                _minx = Math.min.apply(Math, _xx),
                _miny = Math.min.apply(Math, _yy),
                _maxx = Math.max.apply(Math, _xx),
                _maxy = Math.max.apply(Math, _yy);
                var _scale = Math.min( (paper.view.size.width - 2 * this.renkan.options.autoscale_padding) / (_maxx - _minx), (paper.view.size.height - 2 * this.renkan.options.autoscale_padding) / (_maxy - _miny));
                this.initialScale = _scale;
                // Override calculated scale if asked
                if((typeof force_view !== "undefined") && parseFloat(force_view.zoom_level)>0 && parseFloat(force_view.offset.x)>0 && parseFloat(force_view.offset.y)>0){
                    this.setScale(parseFloat(force_view.zoom_level), new paper.Point(parseFloat(force_view.offset.x), parseFloat(force_view.offset.y)));
                }
                else{
                    this.setScale(_scale, paper.view.center.subtract(new paper.Point([(_maxx + _minx) / 2, (_maxy + _miny) / 2]).multiply(_scale)));
                }
            }
            if (nodes.length === 1) {
                this.setScale(1, paper.view.center.subtract(new paper.Point([nodes.at(0).get("position").x, nodes.at(0).get("position").y])));
            }
        },
        paperShift: function(_delta) {
            this.offset = this.offset.add(_delta);
            this.renderer.redraw();
        },
        updateUrl: function(){
            if(this.options.url_parameters && this.options.update_url){
                var result = {};
                var parameters = Backbone.history.getFragment().split('?');
                if (parameters.length > 1){
                    parameters[1].split("&").forEach(function(part) {
                        var item = part.split("=");
                        result[item[0]] = decodeURIComponent(item[1]);
                    });
                }
                result.view = Math.round(this.offset.x*1000)/1000 + ',' + Math.round(this.offset.y*1000)/1000 + ',' + Math.round(this.scale*1000)/1000;

                if (this.renkan.project.get("views").indexOf(this.model) > -1){
                    result.viewIndex = this.renkan.project.get("views").indexOf(this.model);
                    if (result.viewIndex === this.renkan.project.get("views").length - 1){
                        result.viewIndex = -1;
                    }
                } else {
                    if (result.viewIndex){
                        delete result.viewIndex;
                    }
                }
                this.renkan.router.navigate("?" + decodeURIComponent($.param(result)), {trigger: false, replace: true});
            }
        },
        destroy: function(_event) {
            this._super("destroy");
            this.showNodes(false);
        }
    }).value();

    return ViewRepr;

});
