1 module logger;
2 
3 import std.conv;
4 import std.stdio;
5 import std.traits;
6 
7 import deimos.ncurses;
8 
9 /**
10  * Provides static logging of dynamic values
11  *
12  * A replacement for writelning the same value every tick.
13  *
14  * Imperatives:
15  *   - Must provide static-looking value prints
16  *   - Must be usable in concert with standard io functions
17  *     May have to compromise this
18  */
19 class Logger {
20 	private {
21 		string[string] values;
22 		WINDOW* varWindow;
23 		WINDOW* logWindow;
24 
25 		@property int VAR_WINDOW_HEIGHT() {
26 			return cast(int)values.length + 1;
27 		}
28 	}
29 
30 	this() {
31 		initscr();
32 		noecho();
33 		curs_set(0);
34 
35 		varWindow = newwin(VAR_WINDOW_HEIGHT, COLS, 0, 0);
36 		logWindow = newwin(
37 			LINES - VAR_WINDOW_HEIGHT, COLS,
38 			VAR_WINDOW_HEIGHT, 0
39 		);
40 		scrollok(logWindow, true);
41 		refresh();
42 	}
43 
44 	~this() {
45 		curs_set(1);
46 		delwin(varWindow);
47 		delwin(logWindow);
48 		endwin();
49 	}
50 
51 	public void setValue(T)(string key, T value) {
52 		if (key !in values) {
53 			wresize(varWindow, VAR_WINDOW_HEIGHT + 1, COLS);
54 			wresize(logWindow, LINES - VAR_WINDOW_HEIGHT - 1, COLS);
55 			mvwin(logWindow, VAR_WINDOW_HEIGHT + 1, 0);
56 		}
57 
58 		values[key] = value.to!string;
59 		render();
60 	}
61 
62 	public void delValue(string key) {
63 		values.remove(key);
64 	}
65 
66 	public void clearValues() {
67 		values.clear();
68 	}
69 
70 	public void writeln(A...)(A a) {
71 		writeNoRefresh(a);
72 		waddch(logWindow, '\n');
73 		wrefresh(logWindow);
74 	}
75 
76 	public void write(A...)(A a) {
77 		writeNoRefresh(a);
78 		wrefresh(logWindow);
79 	}
80 
81 	private void writeNoRefresh(A...)(A a) {
82 		foreach (arg; a) {
83 			static if (isSomeChar!(typeof(arg))) {
84 				waddch(logWindow, arg);
85 			} else static if (__traits(isFloating, arg)) {
86 				wprintw(logWindow, "%f", arg);
87 			} else static if (__traits(isIntegral, arg)) {
88 				wprintw(logWindow, "%d", arg);
89 			} else static if (isSomeString!(typeof(arg))) {
90 				wprintw(logWindow, "%.*s", arg.length, arg.ptr);
91 			}
92 		}
93 	}
94 
95 	private void render() {
96 		wmove(varWindow, 0, 0);
97 		foreach (key, val; values) {
98 			wprintw(
99 				varWindow,
100 				"%.*s: %.*s\n",
101 				key.length, key.ptr,
102 				val.length, val.ptr
103 			);
104 		}
105 
106 		foreach (x; 0 .. COLS) {
107 			waddch(varWindow, '-');
108 		}
109 
110 		wrefresh(varWindow);
111 		wrefresh(logWindow);
112 		refresh();
113 	}
114 }