var Graph = new Class({
    
    'initialize': function(options) {
        this.mapScale = 0.05;
        this.throwMultiplier = 2;
        this.id = options.id;
        this.isPanning = false;
        var drag = new Drag.Move(this.id + '-field', { 'handle': this.id });
        drag.addEvent('onStart', this.cursorHandClose.bind(this));
        drag.addEvent('onDrag', this.dragHandler.bind(this));
        drag.addEvent('onComplete', this.cursorHandOpen.bind(this));
        drag.addEvent('onComplete', this.throwStart.bind(this));
        this.panDrag = drag;
        document.addEvent('mousemove', this.throwObserver.bind(this));
        document.addEvent('keydown', this.keyPressHandler.bind(this));
        window.addEvent('resize', this.resize.bind(this));
        
        this.gotoFx = new Fx.Styles(this.id + '-field', {
            'duration': 1000,
            'transition': Fx.Transitions.Quart.easeOut
        });
        
        this.throwFx = new Fx.Styles($(this.id + '-field'), {
            'duration': 500,
            'transition': Fx.Transitions.Circ.easeOut
        });
        
        this.resize();
        this.cursorHandOpen();
        this.fixLinks();
        this.mapInitialize();
    },
    
    'dragHandler': function() {
        $(this.id).addClass('dragging');
        this.isPanning = true;
    },
    
    'fixLinks': function() {
        $$('a').each(function(link) {
            link.addEvent('mouseup', this.checkIfPanning.bind(this));
        }.bind(this));
    },
    
    'checkIfPanning': function(e) {
        var event = new Event(e);
        var target = event.target;
        if (this.isPanning) {
            var clickHandler = function(event) {
                var event = new Event(event);
                event.preventDefault();
                target.removeEvent('click', clickHandler);
            };
            target.addEvent('click', clickHandler);
        }
    },
    
    'keyPressHandler': function(e) {
        if ($('search').hasClass('focused')) {
            return;
        }
        var event = new Event(e);
        event = this.fixWebkitEventKey(event);
        var pos = $(this.id + '-field').getPosition();
        switch (event.key) {
            case 'h':
                this.goto(0, 0); break;
            case 'up':
                this.goto(pos.x, pos.y + 400); break;
            case 'down':
                this.goto(pos.x, pos.y - 400); break;
            case 'left':
                this.goto(pos.x + 400, pos.y); break;
            case 'right':
                this.goto(pos.x - 400, pos.y); break;
        }
    },
    
    'fixWebkitEventKey': function(e) {
        if (e.code == 63232) {
            e.key = 'up';
        } else if (e.code == 63233) {
            e.key = 'down';
        } else if (e.code == 63234) {
            e.key = 'left';
        } else if (e.code == 63235) {
            e.key = 'right';
        }
        return e;
    },
    
    'goto': function(x, y) {
        this.gotoFx.start({
            'left': x,
            'top': y
        });
        this.mapGotoFx.start({
            'left': x * this.mapScale,
            'top': y * this.mapScale
        });
    },
    
    'resize': function() {
        $(this.id).setStyles({
            'width': window.getSize().size.x,
            'height': window.getSize().size.y
        });
    },
    
    'cursorHandOpen': function() {
        $(this.id).removeClass('dragging');
        if (window.gecko) {
            $(this.id).setStyle('cursor', '-moz-grab');
        } else if (window.webkit) {
            $(this.id).setStyle('cursor', 'auto');
        } else {
            $(this.id).setStyle('cursor', 'url(images/hand-open.cur)');
        }
        this.isPanning = false;
    },
    
    'cursorHandClose': function() {
        if (window.gecko) {
            $(this.id).setStyle('cursor', '-moz-grabbing');
        } else if (window.webkit) {
            $(this.id).setStyle('cursor', 'move');
        } else {
            $(this.id).setStyle('cursor', 'url(images/hand-closed.cur)');
        }
        $('search').focus();
        $('search').blur();
    },
    
    'throwObserver': function(e) {
        var event = new Event(e);
        if (this.isThrown) {
            var dx = event.page.x - this.throwOrigin.x;
            var dy = event.page.y - this.throwOrigin.y;
            var pos = $(this.id + '-field').getPosition();
            var throwPos = {
                'x': pos.x + dx * this.throwMultiplier,
                'y': pos.y + dy * this.throwMultiplier
            };
            this.isThrown = false;
            this.throwFx.start({
                'left': throwPos.x,
                'top':  throwPos.y
            });
            this.mapThrowFx.start({
                'left': throwPos.x * this.mapScale,
                'top':  throwPos.y * this.mapScale
            });
        } else {
            this.throwOrigin = {
                'x': event.page.x,
                'y': event.page.y
            };
        }
    },
    
    'throwStart': function() {
        this.isThrown = true;
    },
    
    'mapInitialize': function() {
        
        var scale = this.mapScale;
        
        var map = $(this.id + '-map');
        var field = $(this.id + '-field');
        
        map.setStyles({
            'overflow': 'hidden'
        });
        
        var mapSize = map.getSize().size;
        var fieldSize = field.getSize().size;
        var mapViewSize = {
            'x': window.getWidth() * scale,
            'y': window.getHeight() * scale
        };
        
        var relative = new Element('div', {
            'styles': {
                'position': 'relative',
                'left': mapSize.x / 2 - mapViewSize.x / 2,
                'top': mapSize.y / 2 - mapViewSize.y / 2
            }
        });
        relative.injectInside(map);
        
        var mapField = new Element('div', {
            'styles': {
                'position': 'absolute',
                'width': fieldSize.x * scale,
                'height': fieldSize.y * scale,
                'left': 0,
                'top': 0
            }
        });
        mapField.injectInside(relative);
        
        field.getElements('.graph-box').each(function(node) {
            var nodePos = node.getPosition();
            if (node.hasClass('project')) {
                nodeSize = {
                    'x': 320,
                    'y': 260
                };
            } else {
                var nodeSize = node.getSize().size;
            }
            var element = new Element('div', {
                'class': 'graph-map-box',
                'styles': {
                    'position': 'absolute',
                    'width': nodeSize.x * scale,
                    'height': nodeSize.y * scale,
                    'left': nodePos.x * scale,
                    'top': nodePos.y * scale
                }
            });
            element.injectInside(mapField);
        });
        
        var mapView = new Element('div', {
            'class': 'graph-map-view',
            'styles': {
                'position': 'absolute',
                'width': mapViewSize.x,
                'height': mapViewSize.y,
                'left': 0,
                'top': 0
            }
        });
        mapView.setOpacity(0.5);
        mapView.injectInside(relative);
        
        var mapDimensions 
        
        var mapOpen = new Element('a', {
            'href': '#mapOpen',
            'class': 'graph-map-open',
            'title': 'Show the overview map',
            'styles': {
                'display': 'none',
                'width': 19,
                'line-height': 19,
                'text-align': 'center',
                'text-decoration': 'none'
            }
        });
        mapOpen.setHTML('+');
        mapOpen.injectInside(map);
        
        var mapClose = new Element('a', {
            'href': '#mapClose',
            'class': 'graph-map-close',
            'title': 'Hide the overview map',
            'styles': {
                'position': 'absolute',
                'left': map.getPosition().x + map.getSize().size.x - 16,
                'bottom': map.getSize().size.y - 16
            }
        });
        mapClose.setHTML('&times;');
        mapClose.injectInside(map);
        
        mapOpen.addEvent('click', function(e) {
            var event = new Event(e);
            event.preventDefault();
            mapField.style.display = 'block';
            mapOpen.style.display = 'none';
            mapClose.style.display = 'inline';
            map.setStyles({
                'width': mapSize.x,
                'height': mapSize.y
            });
        });
        
        mapClose.addEvent('click', function(e) {
            var event = new Event(e);
            event.preventDefault();
            mapField.style.display = 'none';
            mapOpen.style.display = 'block';
            mapClose.style.display = 'none';
            map.setStyles({
                'width': 'auto',
                'height': 'auto'
            });
        });
        
        var drag = new Drag.Move(mapField, { 'handle': map });
        drag.addEvent('onComplete', function() {
            var mapPos = {
                'x': parseInt(mapField.getStyle('left')),
                'y': parseInt(mapField.getStyle('top'))
            };
            console.log(mapPos);
            this.goto(mapPos.x / scale, mapPos.y / scale);
        }.bind(this));
        
        window.addEvent('resize', function() {
            mapView.setStyles({
                'width': window.getWidth() * scale,
                'height': window.getHeight() * scale
            });
        });
        
        var updateMap = function() {
            mapField.setStyles({
                'left': parseInt(field.getStyle('left')) * scale,
                'top': parseInt(field.getStyle('top')) * scale
            });
        }.bind(this);
        
        this.panDrag.addEvent('onDrag', updateMap);
        this.mapGotoFx = new Fx.Styles(mapField, {
            'duration': 1000,
            'transition': Fx.Transitions.Quart.easeOut
        });
        this.mapThrowFx = new Fx.Styles(mapField, {
            'duration': 500,
            'transition': Fx.Transitions.Circ.easeOut
        });
        
    }
    
});

var graphInstance;
window.addEvent('domready', function() {
    graphInstance = new Graph({
        'id': 'graph'
    });
});
