1 var define = require("../define").define,
  2         Collection = require("./Collection"),
  3         base = require("../base");
  4 
  5 var padding = function(char, numSpaces) {
  6     var ret = [];
  7     for (var i = 0; i < numSpaces; i++)
  8         ret.push(char);
  9     return ret.join("");
 10 };
 11 
 12 module.exports = exports = define(Collection, {
 13     instance : {
 14         /**@lends comb.collections.Heap.prototype*/
 15         __getParentIndex : function(index) {
 16             return Math.floor((index - 1) / 2);
 17         },
 18 
 19         __getLeftChildIndex : function(index) {
 20             return (index * 2) + 1;
 21         },
 22 
 23         __getRightChildIndex : function(index) {
 24             return (index * 2) + 2;
 25         },
 26 
 27         __makeNode : function(key, value) {
 28             return {key : key, value : value};
 29         },
 30 
 31 
 32         /**
 33          * Base class for Heap Implementations.
 34          *
 35          *
 36          * @constructs
 37          * @augments comb.collections.Collection
 38          * @memberOf comb.collections
 39          *
 40          * @property {Number} count the current number of elements.
 41          * @property {Array} keys the keys of all items in the heap.
 42          * @property {Array} values the values contained in the heap.
 43          * @property {Boolean} isEmpty true if the Heap is empty.
 44          */
 45         constructor : function() {
 46             this.__heap = [];
 47         },
 48 
 49         /**
 50          * Insert a key value into the key
 51          * @param key
 52          * @param value
 53          */
 54         insert : function(key, value) {
 55             if (!base.isString(key)) {
 56                 var l = this.__heap.push(this.__makeNode(key, value));
 57                 this.__upHeap(l - 1);
 58             } else {
 59                 throw TypeError("Invalid key");
 60             }
 61         },
 62 
 63         /**
 64          * Removes the root from the heap
 65          *
 66          * @returns the value of the root
 67          */
 68         remove : function() {
 69             var ret = undefined, heap = this.__heap, l = heap.length;
 70             if (l) {
 71                 ret = heap[0];
 72                 if (l == 1) {
 73                     heap.length = 0;
 74                 } else {
 75                     heap[0] = heap.pop();
 76                     this.__downHeap(0);
 77                 }
 78             }
 79             return ret ? ret.value : ret;
 80         },
 81 
 82         /**
 83          * Gets he value of the root node with out removing it.
 84          *
 85          * @returns the value of the root
 86          */
 87         peek : function() {
 88             var ret = undefined, heap = this.__heap, l = heap.length;
 89             if (l) {
 90                 ret = heap[0];
 91             }
 92             return ret ? ret.value : ret;
 93         },
 94 
 95         /**
 96          * Gets the key of the root node without removing it.
 97          *
 98          * @returns the key of the root
 99          */
100         peekKey : function() {
101             var ret = undefined, heap = this.__heap, l = heap.length;
102             if (l) {
103                 ret = heap[0];
104             }
105             return ret ? ret.key : ret;
106         },
107 
108         /**
109          * Perform the heapify operation after the an
110          * item as been added to the bottom of the heap.
111          *
112          * @param index the index in which the new item was added
113          */
114         __upHeap : function(index) {
115             throw Error("NOT IMPLEMENTED");
116         },
117 
118         /**
119          * Heapify the heap after the root has been removed
120          *
121          * @param index the index of the root
122          */
123         __downHeap : function(index) {
124             throw Error("NOT IMPLEMENTED");
125         },
126 
127         /**
128          *
129          * Determine if the heap contains a particular key.
130          *
131          * @param key key to test.
132          *
133          * @returns {Boolean} true if the key is contained in this heap.
134          */
135         containsKey : function(key) {
136             var heap = this.__heap;
137             for (var i = heap.length - 1; i >= 0; i--) {
138                 if (heap[i].key == key) {
139                     return true;
140                 }
141             }
142             return false;
143         },
144 
145         /**
146          *
147          * Determine if the heap contains a particular value.
148          *
149          * @param value value to test.
150          *
151          * @returns {Boolean} true if the value is contained in this heap.
152          */
153         containsValue : function(value) {
154             var heap = this.__heap;
155             for (var i = heap.length - 1; i >= 0; i--) {
156                 if (heap[i].value == value) {
157                     return true;
158                 }
159             }
160             return false;
161         },
162 
163         /**
164          * Empty the heap.
165          */
166         clear : function() {
167             this.__heap.length = 0;
168         },
169 
170         __printNode : function(index, level) {
171             //console.log(level);
172             var str = [], node = this.__heap[index];
173             if (node == null || node == undefined) {
174                 str.push(padding('\t', level));
175                 str.push("~");
176                 console.log(str.join(""));
177             } else {
178                 this.__printNode(this.__getRightChildIndex(index), level + 1);
179                 str.push(padding('\t', level));
180                 str.push(node.key + " : " + node.value + "\n");
181                 console.log(str.join(""));
182                 this.__printNode(this.__getLeftChildIndex(index), level + 1);
183             }
184         },
185 
186         /**
187          * Print the heap.
188          */
189         print : function() {
190             this.__printNode(0, 0);
191         },
192 
193         getters : {
194 
195             count : function() {
196                 return this.__heap.length;
197             },
198 
199             keys : function() {
200                 return this.__heap.map(function(n) {
201                     return n.key;
202                 });
203             },
204 
205             values : function() {
206                 return this.__heap.map(function(n) {
207                     return n.value;
208                 });
209             },
210 
211             isEmpty : function() {
212                 return this.__heap.length == 0;
213             }
214         }
215 
216 
217     }
218 });