1#! /bin/bash
2
3# Functions
4function init_vars {
5	if [ "${LDRAW_CAT_HI_RES}" != "" ]; then
6		export CATALOG_DIR=${HOME}/tmp/LDrawCatalog-high
7	else
8		export CATALOG_DIR=${HOME}/tmp/LDrawCatalog
9	fi
10	export LAST_DIR=${CATALOG_DIR}/last
11	export IMG_DIR=${CATALOG_DIR}/img
12	export FULL_DIR=${CATALOG_DIR}/full
13	export CAT_DIR=${CATALOG_DIR}/cat
14	export CSS_FILENAME=LDrawPartsCatalog.css
15	export MAIN_FILENAME=LDrawPartsCatalog.html
16	export FULL_FILENAME=LDrawOfflinePartsCatalog.html
17	export CATALOG=${CATALOG_DIR}/${MAIN_FILENAME}
18	export FULL_CATALOG=${FULL_DIR}/${FULL_FILENAME}
19	export CATEGORY_BASE=${CAT_DIR}/LDraw
20	export ALL_PARTS_LIST=${CATALOG_DIR}/AllLDrawParts.txt
21	export LAST_ALL_PARTS_LIST=${LAST_DIR}/AllLDrawParts.txt
22	export PARTS_LIST=${CATALOG_DIR}/LDrawParts.txt
23	export LAST_PARTS_LIST=${LAST_DIR}/LDrawParts.txt
24	export BASEPLATES_LIST=${CATALOG_DIR}/LDrawBaseplates.txt
25	export LAST_BASEPLATES_LIST=${LAST_DIR}/LDrawBaseplates.txt
26	export PANELS_LIST=${CATALOG_DIR}/LDrawPanels.txt
27	export LAST_PANELS_LIST=${LAST_DIR}/LDrawPanels.txt
28	export CATEGORIES_LIST=${CATALOG_DIR}/Categories.txt
29	export LDRAW_DIR=${HOME}/Library/ldraw
30	export LDVIEW=/Applications/LDView.app/Contents/MacOS/LDView
31}
32
33function print_part_row {
34	png_filename=${part_filename%.dat}.png
35	png_size=`file "${IMG_DIR}/${png_filename}" | cut -d , -f 2`
36	png_width=`echo ${png_size} | cut -d ' ' -f 1`
37	png_height=`echo ${png_size} | cut -d ' ' -f 3`
38	if [ "${LDRAW_CAT_HI_RES}" != "" ]; then
39		(( png_width /= 2 ))
40		(( png_height /= 2 ))
41	fi
42	if [ "${keywords}" != "" ]; then
43		rowspan=3
44	else
45		rowspan=2
46	fi
47	echo '		<tr valign="top">
48			<td rowspan='${rowspan}' align="right"><img width="'${png_width}'" height="'${png_height}'" src="../img/'${png_filename}'" alt="Part Image"/></td>
49			<td class="label" align="right" height="99%"><font size="-2">File</font></td><td>'${part_filename}'</td>
50		</tr>
51		<tr valign="top"><td class="label" align="right"><font size="-2">Name</font></td><td>'${desc}'</td></tr>'
52	if [ "${keywords}" != "" ]; then
53		echo '		<tr valign="top"><td class="label" align="right"><font size="-2">Keywords</font></td><td>'${keywords}'</td></tr>'
54	fi
55}
56
57function get_part_desc {
58	if [ -e "${1}" ]; then
59		part_desc=`head -n 1 ${1} | sed 's/
60$//' | sed -E 's/^0[ 	]+//' | tr -d '\n'`
61		if [[ "${part_desc}" =~ ^~Moved\ to\  ]]; then
62			old_part_desc=${part_desc}
63			new_part=`echo "${part_desc}" | sed -E 's/~Moved to //'`
64			get_part_desc "${new_part}.dat"
65		fi
66	fi
67}
68
69function process_part {
70	get_vars_from_line ${*}
71	export CATEGORY_FILE=${CATEGORY_BASE}${cat}.html
72	print_part_row >> "${CATEGORY_FILE}"
73	print_part_row >> "${FULL_CATALOG}"
74}
75
76function pre_process_part {
77	get_vars_from_line ${*}
78	get_part_desc ${part_filename}
79	if [[ "${part_desc}" =~ [Bb][Aa][Ss][Ee][Pp][Ll][Aa][Tt][Ee] ]]; then
80		if [ "${cmdline}" == "" ]; then
81			echo ${part_filename} >> ${BASEPLATES_LIST}
82		else
83			echo ${part_filename}${cmdline} >> ${BASEPLATES_LIST}-cmdline
84		fi
85	elif [[ "${part_filename}" =~ ^(4864|6268|4215|2362|4865|4345ap|4345bp)[^0-9] ]]; then
86		if [ "${cmdline}" == "" ]; then
87			echo ${part_filename} >> ${PANELS_LIST}
88		else
89			echo ${part_filename}${cmdline} >> ${PANELS_LIST}-cmdline
90		fi
91	else
92		if [ "${cmdline}" == "" ]; then
93			echo ${part_filename} >> ${PARTS_LIST}
94		else
95			echo ${part_filename}${cmdline} >> ${PARTS_LIST}-cmdline
96		fi
97	fi
98}
99
100function find_meta_value {
101	meta_value=`grep -E '^[ 	]*0[ 	]+\'$2'[ 	]+' $1 | sed -E -e 's/^[ 	]*0[ 	]+\'$2'[ 	]+//' -e 's/
102//g'`
103}
104
105function find_category {
106	find_meta_value $1 "!CATEGORY"
107	if [ "${meta_value}" == "" ]; then
108		part_cat=`echo ${orig_part_desc} | cut -f 1 -d ' ' | sed -E 's/^[_~=]+//'`
109	else
110		part_cat=$meta_value
111	fi
112}
113
114function find_cmdline {
115#	find_meta_value $1 "!CMDLINE"
116#	if [ "${meta_value}" != "" ]; then
117#		part_cmdline=${meta_value}
118#	else
119#		unset part_cmdline
120#	fi
121	unset part_cmdline
122}
123
124function find_keywords {
125	meta_value=`grep -E '^[ 	]*0[ 	]+\!KEYWORDS[ 	]+' $1 | sed -E -e 's/^[ 	]*0[ 	]+\!KEYWORDS[ 	]+//' -e 's/
126//g' -e 's/$/, /'`
127	if [ "${meta_value}" != "" ]; then
128		part_keywords=`echo ${meta_value} | sed 's/,$//'`
129	else
130		unset part_keywords
131	fi
132}
133
134function print_part_scan {
135	orig_part_desc=`head -n 1 ${1} | sed 's/
136$//' | sed -E 's/^0[ 	]+//' | tr -d '\n'`
137	find_category $1
138	find_cmdline $1
139	find_keywords $1
140	echo -e ${part_cat}${orig_part_desc}${1}${part_cmdline}${part_keywords}
141}
142
143function scan_part {
144	print_part_scan $1 >> ${ALL_PARTS_LIST}
145}
146
147function print_style_sheet {
148echo 'body
149{
150	font-family: tahoma, sans-serif;
151}
152
153p
154{
155	margin-top: 0px;
156	margin-bottom: 0px;
157}
158
159div
160{
161	position: absolute;
162}
163
164table
165{
166	border-collapse: collapse;
167	border: 2px solid #000000;
168	background-color: #FFFFFF;
169	padding: 0px;
170}
171
172tr
173{
174	page-break-inside: avoid;
175}
176
177th
178{
179	background-color: #0080D0;
180	color: #FFFFFF;
181	border-bottom: 1px solid #000000;
182	border-right: 1px solid #00558A;
183	padding: 4px 8px;
184}
185
186th.title
187{
188	background-color: #EEEEEE;
189	color: #000000;
190	font-size: 150%;
191}
192
193td
194{
195	background-color: #FFFFFF;
196	border-bottom: 1px solid #BFBFBF;
197	border-right: 1px solid #BFBFBF;
198	padding: 2px 4px;
199}
200
201td.label
202{
203	text-align: right;
204	border-right: 0px;
205	width: 1%;
206	padding: 2px 0px 2px 4px;
207}
208
209table.credits
210{
211	border-collapse: collapse;
212	border-style: none;
213	background-color: transparent;
214	margin: 0px;
215	width: 100%;
216}
217
218td.credits
219{
220	background-color: #EEEEEE;
221	border-style: none;
222	padding: 0px;
223}
224
225table.credits td
226{
227	background-color: transparent;
228	color: #808080;
229	border-style: none;
230	font-size: 65%;
231}
232
233a
234{
235	text-decoration: none;
236	border-style: none;
237}
238
239a:link
240{
241	color: #000080;
242}
243
244a:visited
245{
246	color: #0000FF;
247}
248
249a:hover
250{
251	text-decoration: underline;
252	color: #000080;
253}
254
255img
256{
257	float: right;
258}
259
260a img
261{
262	border-style: none;
263}
264
265:link:hover img
266{
267	background-color: #D0E8FF;
268}
269
270:visited:hover img
271{
272	background-color: #A0C0FF;
273}'
274}
275
276function create_style_sheet {
277	print_style_sheet > "${CATALOG_DIR}/${CSS_FILENAME}"
278}
279
280function print_header {
281echo '<!DOCTYPE html>
282<html>
283<head>
284<title>'${1}'</title>'
285echo '<style type="text/css" title="Standard"><!--'
286print_style_sheet
287echo '--></style>'
288#echo '<link href="'${2}${CSS_FILENAME}'" title="Standard" rel="stylesheet" type="text/css">'
289echo '</head>
290<body>'
291}
292
293function print_cat_header {
294	print_header "${*}" ../
295	#echo '<p><a href="../'${MAIN_FILENAME}'">Back</a></p>'
296	echo '<table>
297	<thead>
298		<tr>
299			<th colspan="3">'${*}'</th>
300		</tr>
301	</thead>
302	<tbody>'
303}
304
305function print_full_header {
306	print_header "${*}" ../
307	echo '<table>
308	<tbody>'
309}
310
311function print_main_header {
312	print_header "${*}"
313echo '<table>
314	<thead>
315		<tr>
316			<th>Category</th>
317		</tr>
318	</thead>
319	<tbody>'
320}
321
322function create_main_header {
323	rm -f ${CATALOG}
324	print_main_header LDraw Parts > "${CATALOG}"
325}
326
327function create_full_header {
328	rm -f ${CATALOG}
329	print_full_header LDraw Parts > "${FULL_CATALOG}"
330}
331
332function create_cat_header {
333	export CATEGORY_FILE=${CATEGORY_BASE}${1}.html
334	rm -f ${CATEGORY_FILE}
335	print_cat_header ${1} > "${CATEGORY_FILE}"
336}
337
338function print_footer {
339echo '	</tbody>
340</table>
341</body>
342</html>'
343}
344
345function create_cat_footer {
346	export CATEGORY_FILE=${CATEGORY_BASE}${1}.html
347	print_footer >> "${CATEGORY_FILE}"
348}
349
350function create_full_footer {
351	print_footer >> "${FULL_CATALOG}"
352}
353
354function create_main_footer {
355	print_footer >> "${CATALOG}"
356}
357
358function create_images {
359	image_size=512
360	edge_thickness=1
361	if [ "${LDRAW_CAT_HI_RES}" != "" ]; then
362		image_size=1024
363		edge_thickness=2
364	fi
365	while [ `stat -f %z ${1}` -gt 0 ]
366	do
367		ldview_command_line="${LDVIEW} -LDrawDir=${LDRAW_DIR} ${2} -FOV=0.1 -SaveSnapshots=1 -SaveDir=${IMG_DIR} -SaveWidth=${image_size} -SaveHeight=${image_size} -EdgeThickness=${edge_thickness} -SaveZoomToFit=1 -AutoCrop=1 -SaveAlpha=1 -LineSmoothing=1 -BFC=0 -PreferenceSet=LDPartsCatalog `head -n 50 ${1}`"
368		$ldview_command_line
369		if [ $? != 0 ]; then
370			# LDView occasionally just stops in the middle. Since that is going
371			# to be a really hard bug to track down, retry the LDView command
372			# if it fails the first time.
373			echo LDView failed. Trying one more time.
374			$ldview_command_line
375		fi
376		tail -n +51 ${1} > ${1}.tmp
377		mv ${1}.tmp ${1}
378	done
379	rm -f "${1}"
380	while read line
381	do
382		get_cmdline_vars_from_line ${line}
383		if [[ "${cmdline}" =~ ^-[cC](.*) ]]; then
384			default_color=-DefaultColorNumber=${BASH_REMATCH[1]}
385		else
386			unset default_color
387		fi
388		ldview_command_line="${LDVIEW} -LDrawDir=${LDRAW_DIR} ${2} -FOV=0.1 -SaveSnapshots=1 -SaveDir=${IMG_DIR} -SaveWidth=${image_size} -SaveHeight=${image_size} -EdgeThickness=${edge_thickness} -SaveZoomToFit=1 -AutoCrop=1 -SaveAlpha=1 -LineSmoothing=1 -BFC=0 ${default_color} ${part_filename}"
389		$ldview_command_line
390	done < "${1}-cmdline"
391	rm -f "${1}-cmdline"
392}
393
394function create_empty_list {
395	rm -f ${1}
396	touch ${1}
397}
398
399function create_empty_lists {
400	create_empty_list ${ALL_PARTS_LIST}
401	create_empty_list ${PARTS_LIST}
402	create_empty_list ${PARTS_LIST}-cmdline
403	create_empty_list ${BASEPLATES_LIST}
404	create_empty_list ${BASEPLATES_LIST}-cmdline
405	create_empty_list ${PANELS_LIST}
406	create_empty_list ${PANELS_LIST}-cmdline
407}
408
409function process_parts {
410	while read line
411	do
412		process_part ${line}
413	done < "${ALL_PARTS_LIST}"
414}
415
416function pre_process_parts {
417	if [ -e ${LAST_PARTS_LIST} ] && [ -e ${LAST_PARTS_LIST}-cmdline ] && [ -e ${LAST_BASEPLATES_LIST} ] && [ -e ${LAST_BASEPLATES_LIST}-cmdline ] && [ -e ${LAST_PANELS_LIST} ] && [ -e ${LAST_PANELS_LIST}-cmdline ]; then
418		cp ${LAST_PARTS_LIST} ${PARTS_LIST}
419		cp ${LAST_PARTS_LIST}-cmdline ${PARTS_LIST}-cmdline
420		cp ${LAST_BASEPLATES_LIST} ${BASEPLATES_LIST}
421		cp ${LAST_BASEPLATES_LIST}-cmdline ${BASEPLATES_LIST}-cmdline
422		cp ${LAST_PANELS_LIST} ${PANELS_LIST}
423		cp ${LAST_PANELS_LIST}-cmdline ${PANELS_LIST}-cmdline
424		return
425	fi
426	echo Preprocessing part information...
427	while read line
428	do
429		pre_process_part ${line}
430	done < "${ALL_PARTS_LIST}"
431	cp ${PARTS_LIST} ${LAST_DIR}/
432	cp ${PARTS_LIST}-cmdline ${LAST_DIR}/
433	cp ${BASEPLATES_LIST} ${LAST_DIR}/
434	cp ${BASEPLATES_LIST}-cmdline ${LAST_DIR}/
435	cp ${PANELS_LIST} ${LAST_DIR}/
436	cp ${PANELS_LIST}-cmdline ${LAST_DIR}/
437}
438
439function process_command_line {
440	if [ "${1}" == "-hi" ]; then
441		echo Generating high-resolution images.
442		LDRAW_CAT_HI_RES=1
443	else
444		unset LDRAW_CAT_HI_RES
445	fi
446}
447
448function verify_dir {
449	if [ ! -d "${1}" ]; then
450		mkdir -p "${1}"
451	fi
452	if [ ! -d "${1}" ]; then
453		echo Error creating directory ${1}.
454		exit
455	fi
456}
457
458function verify_settings {
459	verify_dir "${LAST_DIR}"
460	verify_dir "${CATALOG_DIR}"
461	verify_dir "${IMG_DIR}"
462	verify_dir "${CAT_DIR}"
463	verify_dir "${FULL_DIR}"
464	if [ ! -d ${LDRAW_DIR} ]; then
465		echo LDraw directory not found at ${LDRAW_DIR}
466		exit
467	fi
468}
469
470function scan_parts {
471	cd ${LDRAW_DIR}/parts
472	if [ -e ${LAST_ALL_PARTS_LIST} ]; then
473		cp ${LAST_ALL_PARTS_LIST} ${ALL_PARTS_LIST}
474	else
475		echo Scanning parts...
476		for partFile in *.dat
477		do
478			scan_part ${partFile}
479		done
480		echo Sorting parts list...
481		# Set locale to UTF-8 for sorting, since LDraw officially uses UTF-8
482		export LC_ALL=UTF-8
483		sort -f ${ALL_PARTS_LIST} > ${ALL_PARTS_LIST}.tmp
484		mv ${ALL_PARTS_LIST}.tmp ${ALL_PARTS_LIST}
485		cp ${ALL_PARTS_LIST} ${LAST_ALL_PARTS_LIST}
486	fi
487	cut -d  -f 1 ${ALL_PARTS_LIST} | sort -u > ${CATEGORIES_LIST}
488}
489
490function generate_part_images {
491	num_imgs=`ls ${IMG_DIR}/ | wc -l`
492	num_parts=`cat ${ALL_PARTS_LIST} | wc -l`
493	if [ ${num_imgs} != ${num_parts} ]; then
494		echo Generating panel part images...
495		create_images ${PANELS_LIST} -cg30,225,275000
496		echo Generating baseplate part images...
497		create_images ${BASEPLATES_LIST} -cg30,45,550000
498		echo Generating standard part images...
499		create_images ${PARTS_LIST} -cg30,45,275000
500	else
501		echo Images already generated.
502	fi
503}
504
505function print_cat_row {
506	echo '		<tr>
507			<td><a href="cat/LDraw'${1/ /%20}'.html">'${*}'</a></td>
508		</tr>'
509}
510
511function create_cat_row {
512	print_cat_row "${*}" >> "${CATALOG}"
513}
514
515function generate_html {
516	echo Generating HTML...
517	create_style_sheet
518	create_full_header
519	create_main_header
520	while read line
521	do
522		create_cat_header "${line}"
523		create_cat_row "${line}"
524	done < "${CATEGORIES_LIST}"
525	create_main_footer
526	process_parts
527	create_full_footer
528	while read line
529	do
530		create_cat_footer ${line}
531	done < "${CATEGORIES_LIST}"
532	echo HTML created.
533}
534
535function get_cmdline_vars_from_line {
536	if [[ "${*}" =~ ([^]*)([^]*) ]]; then
537		part_filename=${BASH_REMATCH[1]}
538		cmdline=${BASH_REMATCH[2]}
539	fi
540}
541
542function get_vars_from_line {
543	if [[ "${*}" =~ ([^]*)([^]*)([^]*)([^]*)([^]*) ]]; then
544		cat=${BASH_REMATCH[1]}
545		desc=${BASH_REMATCH[2]}
546		part_filename=${BASH_REMATCH[3]}
547		cmdline=${BASH_REMATCH[4]}
548		keywords=${BASH_REMATCH[5]}
549	fi
550}
551
552# Main program
553process_command_line ${*}
554init_vars
555verify_settings
556create_empty_lists
557scan_parts
558pre_process_parts
559generate_part_images
560generate_html
561rm -f ${ALL_PARTS_LIST}
562