1 module onsdata.table;
2 
3 import std.stdio;
4 import std.string;
5 import std.conv;
6 
7 import onsdata;
8 
9 class Table(T) {
10 	Row!T[] rows;
11 	private string[] _columns;
12 	size_t[string] colIndex;
13 	
14 	this() {
15 	}
16 	this(size_t aWidth) {
17 		width = aWidth;
18 	}
19 	this(size_t aWidth, size_t aHeight) {
20 		this(aWidth);
21 		height = aHeight;
22 	}
23 	this(size_t aHeight, string[] someColumns) {
24 		this(someColumns.length, aHeight);
25 		columns = someColumns;
26 	}
27 	this(S)(Table!S source, bool copy = false) {
28 		columns = source.columns;
29 		height = source.height;
30 		foreach(i, row; source.rows) {
31 			if (row) rows[i] = newRow;
32 			if (copy) {
33 				foreach(j, c; row.cells) rows[i][j] = to!T(c);
34 			}
35 		}
36 	}
37 	
38 	@property string[] columns() { return _columns; }
39 	@property void columns(string[] values) { 
40 		_columns = values;
41 		width(_columns.length);
42 		foreach(i, col; columns) colIndex[col] = i;
43 	}
44 	
45 	@property void width(size_t aWidth) { _columns.length = aWidth; foreach(row; rows) if (row) row.width = width;  }
46 	@property size_t width() { return _columns.length; }
47 	@property size_t height() { return rows.length; }
48 	@property void height(size_t aHeight) { rows.length = aHeight; }
49 	
50 	size_t count() {
51 		size_t counter = 0;
52 		foreach(row; rows) if (row) counter++;
53 		return counter;
54 	}
55 	auto newRow() {
56 		Row!T result = new Row!T();
57 		result.width = width;
58 		return result;
59 	}
60 	auto newRow(T value) {
61 		auto row = newRow;
62 		row.value(value);
63 		return row;
64 	}
65 	auto newRow(T[] values) {
66 		auto row = newRow;
67 		foreach(i, value; values) row[i] = value;
68 		return row;
69 	}
70 	void add(Row!T row) { row.length = width; rows ~= row; }
71 	
72 	auto firstRow() {
73 		foreach(i, row; rows) if (row) return row;
74 		return null;
75 	}
76 	size_t firstIndex() {
77 		foreach(i, row; rows) if (row) return i;
78 		return size_t.max;
79 	}
80 	size_t lastIndex() {
81 		foreach_reverse(i, row; rows) if (row) return i;
82 		return 0;
83 	}
84 
85 	void opIndexAssign(Row!T row, size_t i) {
86 		if (i < height) rows[i] = row;
87 	}
88 	auto opIndex(size_t i) {
89 		if (i < height) return rows[i];
90 		return newRow; // blää
91 	}
92 	size_t opIndex(string col) {
93 		return colIndex[col];
94 	}
95 	
96 	void min(size_t target, size_t[] cols) { foreach(row; rows) if (row) row.min(target, cols); }
97 	T min(size_t col, size_t start, size_t end) {
98 		bool first = false;
99 		T result = 0;
100 		foreach(row; rows) {
101 			if (row) {
102 				if (!first) {
103 					result = row[col];
104 					first = true;
105 				}
106 				else {
107 					if (result > row[col]) result = row[col];
108 				}
109 			}
110 		}
111 		return result;
112 	}
113 	
114 	void avg(size_t target, size_t[] cols) { foreach(row; rows) if (row) row.avg(target, cols); }
115 	T avg(size_t col, size_t start, size_t end) {
116 		size_t counter = 0;
117 		T result = 0;
118 		foreach(i; start..end) if (auto row = this[i]) {
119 			counter++;
120 			result += row[col];
121 		}
122 		if (counter) return to!T(result/counter);
123 		return 0;
124 	}
125 	
126 	void max(size_t target, size_t[] cols, size_t start = 0, size_t end = 0) { 
127 		auto e = (end == 0 ? height : end);
128 		foreach(i; start..end) if (auto row = this[i]) row.max(target, cols); }
129 	T max(size_t col, size_t start = 0, size_t end = 0) {
130 		auto e = (end == 0 ? height : end);
131 		bool first = false;
132 		T result = 0;
133 		foreach(i; start..end) if (auto row = this[i]) {
134 			if (!first) {
135 				result = row[col];
136 				first = true;
137 			}
138 			else {
139 				if (result < row[col]) result = row[col];
140 			}
141 		}
142 		return result;
143 	}
144 	
145 	void sum(size_t target, size_t[] cols) { foreach(row; rows) if (row) row.sum(target, cols); }
146 	/++
147 	 Sum - Calculating sum of columns in a row
148 	 +/
149 	S sum(S = double)(size_t col, size_t start = 0, size_t end = 0) {
150 		auto e = (end == 0 ? height : end);
151 		int counter = 0; double result = 0;
152 		if (end > height) end = height;
153 		foreach(i; start..e) if (auto row = this[i]) { 
154 			counter++; result += row[col]; }
155 		return to!S((counter) ? result/counter : 0);
156 	}
157 	//	bool sum(T)(T[][] table, size_t target, size_t[] colInds, size_t start = 0, size_t end = size_t.max) { 
158 	//		if (table.length == 0) return false;
159 	//		if (colInds.length == 0) return false;
160 	//		
161 	//		if (end > table.length) end = table.length;
162 	//		auto rlen = table[0].length-1; // max Value for colInds
163 	//		if (target > rlen) return false;
164 	//		foreach(cIndex; colInds) if (cIndex > rlen) return false;
165 	//		
166 	//		double sum = row[cols[0]];
167 	//		foreach(i; start..end) if (auto row = table[i]) {
168 	//			if (cols.length > 1) foreach(col; cols[1..$]) sum += row[col];
169 	//			row[target] = check!T(sum/cols.length);
170 	//		}
171 	//		return true;
172 	//	}
173 	
174 	void delta(string target, string[2] cols, size_t start = 0, size_t end = 0) { delta(this[target], cols, start, end); }
175 	void delta(size_t target, string[2] cols, size_t start = 0, size_t end = 0) { delta(target, [this[cols[0]], this[cols[1]]], start, end); }
176 	void delta(string target, size_t[2] cols, size_t start = 0, size_t end = 0) { delta(this[target], cols, start, end); }
177 	void delta(size_t target, size_t[2] cols, size_t start = 0, size_t end = 0) {
178 		auto e = (end == 0 ? height : end);
179 		foreach(i; start..e) if (auto row = this[i]) row.delta(target, cols); }
180 	
181 	S inc(S = double)(size_t col, size_t start = 0, size_t end = 0) {
182 		auto e = (end == 0 ? height : end);
183 		int counter = 0; int x = 0; bool foundFirst = false;
184 		foreach(i; start..e) if (auto row = this[i]) {
185 			if (i == 0) continue;
186 			
187 			if ((rows[i-1]) && (foundFirst)) {
188 				double delta = row[col] - rows[i-1][col];
189 				if (delta > 0) x++;
190 				counter++;
191 			}
192 			else foundFirst = true;
193 		}
194 		if (counter) return to!S(x/counter);
195 		return 0;
196 	}
197 	
198 	// -- dec
199 	S dec(S = double)(size_t col, size_t start = 0, size_t end = 0) {
200 		auto e = (end == 0 ? height : end);
201 		int counter = 0; int x = 0; bool foundFirst = false;
202 		foreach(i; start..e) if (auto row = this[i]) {
203 			if (i == 0) continue;
204 			
205 			if ((foundFirst) && (this[i-1])) {
206 				double delta = row[col] - this[i-1][col];
207 				if (delta < 0) x++;
208 				counter++;
209 			}
210 			else foundFirst = true;
211 		}
212 		if (counter) return x/counter;
213 		return 0;
214 	}
215 	
216 	// -- div
217 	S div(S = double)(size_t col, size_t start = 0, size_t end = 0) {
218 		auto e = (end == 0 ? height : end);
219 		T[] values; 
220 		foreach(i; start..e) if (auto row = this[i]) {
221 			if (auto row2 = this[i-1]) {
222 				values ~= row2[col] - row[col];
223 			}
224 		}
225 		if (values) {
226 			S result = 0;
227 			foreach(value; values) result += value;
228 			return result/values.length;
229 		}
230 		return 0;
231 	}
232 
233 	Table!T copy() { return new Table!T(this); }
234 	override string toString() {
235 		string result;
236 		result ~= "width:%s\theight:%s\n".format(width, height);
237 		foreach(i, row; rows) if (row) result ~= "%s:\t%s\n".format(i, row.toString);
238 		return result;
239 	}
240 	
241 	T[string][] changedRows(Table!T originalTable) {
242 		T[string][] results; results.length = height; 
243 		foreach(i, row; rows) if (row) results[i] = changedCells(i, originalTable);
244 		return results;
245 	}
246 	
247 	T[string][] changedRows(T originalValue) {
248 		T[string][] results; results.length = height; 
249 		foreach(i, row; rows) if (row) results[i] = changedCells(i, originalValue);
250 		return results;
251 	}
252 	
253 	T[string] changedCells(size_t i, Table!T originalTable) {
254 		T[string] result;
255 		if (auto row = rows[i]) {
256 			if (auto oRow = originalTable[i]) { 
257 				foreach(k, v; colIndex) {	
258 					if (row[v] != oRow[v]) result[k] = row[v];
259 				}
260 			}
261 		}
262 		return result;
263 	}
264 	T[string] changedCells(size_t i, T originalValue) {
265 		T[string] result;
266 		if (auto row = rows[i]) { 
267 			foreach(k, v; colIndex) {	
268 				if (row[v] != originalValue) result[k] = row[v];
269 			}
270 		}
271 		return result;
272 	}
273 	
274 }