function DoublyLinkedList() {
    this._length = 0;
    this._head = null;
    this._tail = null;
    
    this._last_visit = null;
    this._called = false;
}

DoublyLinkedList.prototype = {

	push: function(key, value){
		this.add(key, value);
	},
	/** Add element */
    add: function (key, value){

		        var node = {
		                key: key,
		                value: value,
		                next: null,
		                prev: null
		            };
		
		        if (this._length == 0) {		        	
		            this._head = node;
		            this._tail = node;		            
		        } else {		
		           node.next = this._head;
		           if(this._head != null)
			           this._head.prev = node;
		           this._head = node;		           
		        }        
		
				this.resetIterator();				
		        this._length++;
		    return;
    },
	/* Move element up one */
	moveup: function(value){
		var el = this._head;
		while(el.key != value){
			el = el.next;
		}
		
		if(el.key == value){
			
			if(this._head == el) return;
			
			el.prev.next = el.next;
			el.next = el.prev;
	
			if(el.next.prev != null)
				el.next.prev.next = el;
			else 
				this._head = el;	
				
			el.prev = el.next.prev;
			el.next.prev = el;
			
			if(el.next.next != null)
				el.next.next.prev = el.next;		
			else 
				this._tail = el.next;
			
			el.value--;
			el.next.value++;
			
			return null;
		}
		return null;
	}, 
	/* Move element down */
	movedown: function(value){
		
	},
	/* Print collection  */
	print: function(){
		var tm = this._head;
		var string = tm.key + " == value: " + tm.value + "\n";
				
		while(tm.next != null){
			tm = tm.next;
			string += tm.key + " == value: " + tm.value + "\n";
		}
		
		var value = "";
		if(this._last_visit != null){
			value = this._last_visit.key;
		} 
				
		alert("Results: \n" + string + "\n" + "Last visited: " + value);
	},		
	/* Remove all element in collection */
	del: function(){
		var el = this._tail;
		if(el == null) return;
		
		while(el.prev != null){
			el = el.prev;
			delete el.next;
		}
		delete el;
	},
	/* Set pointer for iterator */	
	setPointer: function(){
		if(!this._called){
			this._called = true;
			this._last_visit = this.head;
		}
	},
	/* Returns next element in collection */
	next: function(){
		if(this._called == false){
			this._called = true;
			this._last_visit = this._head;
			return this._head;
		}
		this._last_visit = this._last_visit.next
		return this._last_visit;
	},	
	/* Checks for next element in collection */
	hasNext: function(){
		if(this._called == false) return !(this._head == null);
		return !(this._last_visit.next == null);
	},
	
	/* Check if key exists in current collection */
	hasKey: function(keyValue){
		this.resetIterator();
		while(this.hasNext()){
			if(this.next().key == keyValue) return true;
		}
		return false;
	},
	/* Returns element by the key */
	getValue: function(keyValue){
		this.resetIterator();
		while(this.hasNext()){
			var c_obj = this.next();
			if(c_obj.key == keyValue) return c_obj.value;
		}
		return null;
	},
	removeLast: function(){
		var el = this._last_visit;
		this._last_visit = el.prev;
		if(this._head == el){
			this._head = el.next;
			if(this._head != null)
				this._head.prev = null;
			delete el;
			return;
		}
		if(this._tail == el){
			this._tail = el.prev;
			if(this._tail != null)
				this._tail.next = null;
			delete el;
			return;
		}
		
		el.prev.next = el.next;	
		el.next.prev = el.prev;
		delete el;
	},
	removeKey: function(keyValue){
		if(this.hasKey(keyValue)){
			this.removeLast();		
		}	
	},
	/* Reset iterator pointer */ 	
	resetIterator: function(){
		this._called = false;
	},
	
	updateValues: function(){
		this.resetIterator();
		var i = 1;
		
		while(this.hasNext()){
			var el = this.next();
			el.value = i;
			try{ $("#num_" + el.key).html(i); } catch(e){}
			el = el.next;
			i++;
		}
	},
	size: function(){
		return this._length;
	}
};