1 module libxlsxd.workbook;
2 
3 import libxlsxd.xlsxwrap;
4 import std.string : toStringz;
5 import std.typecons : refCounted, RefCounted;
6 
7 import libxlsxd.worksheet;
8 import libxlsxd.format;
9 import libxlsxd.chart;
10 import libxlsxd.chartsheet;
11 import libxlsxd.datetime;
12 import libxlsxd.docproperties;
13 
14 alias Workbook = RefCounted!WorkbookImpl;
15 
16 Workbook newWorkbook(string filename) @trusted {
17 	Workbook wb;
18 	wb.filename = filename;
19 	wb.open();
20 	return wb;
21 }
22 
23 struct WorkbookImpl {
24 	WorkbookOpen workBook;
25 
26 	alias workBook this;
27 
28 	~this() @safe {
29 		this.workBook.close();
30 	}
31 }
32 
33 struct WorkbookOpen {
34 	import std.exception : enforce;
35 	import std.datetime : DateTime;
36 	import std.array : empty;
37 	lxw_workbook* handle;
38 	string filename;
39 
40 	Format[string] formats;
41 	Format dateFormat;
42 	Format timeFormat;
43 	Format dateTimeFormat;
44 
45 	static WorkbookOpen opCall(string filename) @safe {
46 		WorkbookOpen ret;
47 		ret.filename = filename;
48 		ret.open();
49 		ret.buildDefaultFormats();
50 		return ret;
51 	}
52 
53 	void open() @trusted {
54 		this.handle = workbook_new(this.filename.toStringz());
55 		this.buildDefaultFormats();
56 	}
57 
58 	void buildDefaultFormats() @safe {
59 		this.dateFormat = this.addFormat();
60 		this.dateFormat.setNumFormat("yyyy-mm-dd");
61 
62 		this.dateTimeFormat = this.addFormat();
63 		this.dateTimeFormat.setNumFormat("yyyy-mm-ddThh:MM:ss");
64 
65 		this.timeFormat = this.addFormat();
66 		this.timeFormat.setNumFormat("hh:MM:ss");
67 	}
68 
69 	void close() @trusted {
70 		if(this.handle !is null) {
71 			workbook_close(this.handle);
72 		}
73 		this.handle = null;
74 	}
75 
76 	WorksheetFluent addFluentWorksheet(string name) @trusted {
77 		return WorksheetFluent(&this, this.addWorksheet(name));
78 	}
79 
80 	Worksheet addWorksheet(string name) nothrow @trusted {
81 		return Worksheet(workbook_add_worksheet(this.handle,
82 					name.empty ? null : name.toStringz()),
83 					&this.dateTimeFormat, &this.dateFormat, &this.timeFormat
84 				);
85 	}
86 
87 	Chartsheet addChartsheet(string name) @trusted {
88 		return Chartsheet(workbook_add_chartsheet(this.handle,
89 					name.empty ? null : name.toStringz())
90 				);
91 	}
92 
93 	Format addFormat() nothrow @nogc @trusted {
94 		return Format(workbook_add_format(this.handle));
95 	}
96 
97 	version(No_Overloads_Or_Templates) {
98 		Format addFormatNamed(string name) nothrow @safe {
99 			return this.addFormatNamedImpl(name);
100 		}
101 	} else {
102 		Format addFormat(string name) nothrow @safe {
103 			return this.addFormatNamedImpl(name);
104 		}
105 	}
106 
107 	private Format addFormatNamedImpl(string name) nothrow @trusted {
108 		auto t = Format(workbook_add_format(this.handle));
109 		this.formats[name] = t;
110 		return t;
111 	}
112 
113 	Format getFormat(string name) nothrow @safe {
114 		return this.formats[name];
115 	}
116 
117 	Chart addChart(ubyte chartType) @nogc nothrow @trusted {
118 		return Chart(workbook_add_chart(this.handle, chartType));
119 	}
120 
121 	void setProperties(DocProperties property) @trusted {
122 		enforce(workbook_set_properties(this.handle, property.handle)
123 				== LXW_NO_ERROR
124 			);
125 	}
126 
127 	version(No_Overloads_Or_Templates) {
128 		void setCustomPropertiesBool(string name, bool b) @safe {
129 			return this.setCustomPropertiesImpl(name, b);
130 		}
131 		void setCustomPropertiesInt(string name, long l) @safe {
132 			return this.setCustomPropertiesImpl(name, l);
133 		}
134 		void setCustomPropertiesNumber(string name, double d) @safe {
135 			return this.setCustomPropertiesImpl(name, d);
136 		}
137 		void setCustomPropertiesDateTime(string name, DateTime d) @safe {
138 			return this.setCustomPropertiesImpl(name, Datetime.fromDateTime(d));
139 		}
140 	} else {
141 		alias setCustomProperties = setCustomPropertiesImpl;
142 	}
143 
144 	private void setCustomPropertiesImpl(T)(string name, T t) @trusted {
145 		import std.traits : isIntegral, isFloatingPoint, isSomeString;
146 		import std.conv : to;
147 
148 		static if(is(T == bool)) {
149 			enforce(workbook_set_custom_property_boolean(this.handle,
150 						name.toStringz(), t
151 					)
152 					== LXW_NO_ERROR
153 				);
154 		} else static if(isIntegral!T) {
155 			enforce(workbook_set_custom_property_integer(this.handle,
156 						name.toStringz(), to!int(t)
157 					)
158 					== LXW_NO_ERROR
159 				);
160 		} else static if(isFloatingPoint!T) {
161 			enforce(workbook_set_custom_property_number(this.handle,
162 						name.toStringz(), to!double(t)
163 					)
164 					== LXW_NO_ERROR
165 				);
166 		} else static if(is(T == Datetime)) {
167 			enforce(workbook_set_custom_property_datetime(this.handle,
168 						toStringz(name), &t.handle)
169 					== LXW_NO_ERROR
170 				);
171 		} else {
172 			static assert(false, "setCustomProperties does not work with '" ~
173 					T.stringof ~ "'");
174 		}
175 	}
176 
177 	void defineName(string name, string formula) @trusted {
178 		enforce(workbook_define_name(this.handle, name.toStringz(),
179 						formula.toStringz()
180 					)
181 				== LXW_NO_ERROR
182 			);
183 	}
184 
185 	Worksheet getWorksheetByName(string name) @trusted {
186 		return Worksheet(workbook_get_worksheet_by_name(this.handle,
187 						name.toStringz()
188 					),
189 					&this.dateTimeFormat, &this.dateFormat, &this.timeFormat
190 				);
191 	}
192 
193 	Chartsheet getChartByName(string name) @trusted {
194 		return Chartsheet(workbook_get_chartsheet_by_name(this.handle,
195 						name.toStringz()
196 					)
197 				);
198 	}
199 
200 	bool validateSheetName(string name) @trusted {
201 		return workbook_validate_sheet_name(this.handle, name.toStringz())
202 				== LXW_NO_ERROR;
203 	}
204 }