<?php

/*
	LXF Gallery Viewer - Upload Community Software
	Copyright (C) 2013 Jordan Smith (gnac.o.matic@gmail.com)

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

error_reporting (E_ALL ^ E_NOTICE);


////////////////////////////////////////////////////////////////////////////////

// This will appear as the page title in both the browser's title bar, and at the top of the webpage.
define ('TITLE',	'LXF Gallery Viewer');

// The subfolder to scan for LXF files, with trailing slash
// (leave blank if this script is in the same folder)
define ('PATH',		'');


////////////////////////////////////////////////////////////////////////////////

/*
- To define a template, use this HEREDOC method (NO INDENTS - very important)

define ('TPL_NAME_HERE',
<<<_TEMPLATE
<div class="{class}">{STR_SITE_NAME}</div>
_TEMPLATE
);

- To call this template in your scripts, use the function "get_template()"

	define ('STR_SITE_NAME', "This is the Name of the Website");
	$class = 'site_heading';
	echo get_template('TPL_NAME_HERE');

- Note the difference in case when referencing {variables} and {CONSTANTS}

- To display HTML / XML, use CDATA tags
*/

define ('TPL__SHELL',
<<<_TEMPLATE
<!DOCTYPE html>
<html>
	<head>
		<title>{TITLE}</title>
		<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
		<style>
			<!--
			body {
				font-family: "Trebuchet MS", Helvetica, sans-serif;
			}

			header {
				margin: 8px;
				padding-bottom: 8px;
				color: #FFF;
				font-size: 48px;
				font-weight: bold;
				text-shadow: #CCC 3px 3px 3px, #CCC -1px 1px 1px, #EEE -1px -1px 1px, #EEE 1px -1px 1px;
				border-bottom: 2px #CCC solid;
			}

			table, tr, td {
				margin: 0;
				padding: 0;
			}

			table {
				margin: 8px;
				padding: 4px;
				border: 1px #CCC solid;
				box-shadow: #CCC 1px 1px 6px;
				float: left;
			}

			table:last-of-type {
				margin-bottom: 16px;
			}

			tr:nth-of-type(1) td {
				margin: -4px;
				padding: 4px;
				max-width: 146px; /* AGH BOX MODEL */
				background: #CCC;
				color: #FFF;
				font-size: 14px;
				font-weight: bold;
				text-align: center;
				white-space: nowrap;
				overflow: hidden;
				text-overflow: ellipsis;
			}

			tr:nth-of-type(2) td {
				text-align: center;
			}

			tr:nth-of-type(n+3) td {
				font-size: 12px;
			}

			tr:nth-of-type(n+3) td:first-of-type {
				padding-right: 2px;
				color: #999;
				font-weight: bold;
				text-align: right;
			}

			tr:nth-of-type(n+3) td:first-of-type:after {
				content: ":";
			}

			footer {
				margin: 8px;
				padding-top: 8px;
				color: #666;
				font-size: 12px;
				font-weight: bold;
				border-top: 2px #CCC solid;
				clear: both;
			}
			-->
		</style>
	</head>
	<body>
		<header>{TITLE}</header>
		{content}
		<footer>This thing was made by <a href="mailto:gnac.o.matic@gmail.com">Gnac</a> (remove this thing if you want, but recognition for useful work often encourages further development)</footer>
	</body>
</html>
_TEMPLATE
);


define ('TPL_LXF',
<<<_TEMPLATE
<table>
	<tr>
		<td colspan="2" title="{title}">{title}</td>
	</tr>
	<tr>
		<td colspan="2">
			<a href="{file}"><img src="data:image/png;base64,{img}" /></a>
		</td>
	</tr>
	<tr>
		<td>Name</td>
		<td>{name}</td>
	</tr>
	<tr>
		<td>Parts</td>
		<td>{parts}</td>
	</tr>
	<tr>
		<td>Version</td>
		<td>{version}</td>
	</tr>
	<tr>
		<td>Brickset</td>
		<td>{brickset}</td>
	</tr>
</table>
_TEMPLATE
);


////////////////////////////////////////////////////////////////////////////////


// Get list of LXF files
$list	= glob (PATH . '*.lxf');

foreach ($list as $file)
{
	$lxf	= array ('xml' => 'IMAGE100.LXFML', 'png' => 'IMAGE100.PNG');

	foreach ($lxf as $t_ext => $t_name)
	{
		$zip	= zip_open ($file);

		do { $t_file = zip_read ($zip); } while ($t_file && zip_entry_name ($t_file) != $t_name);

		zip_entry_open ($zip, $t_file, 'r');

		$t_data		= 'data_' . $t_ext;
		$t_size		= zip_entry_filesize ($t_file);
		$$t_data	= zip_entry_read ($t_file, $t_size);

		zip_entry_close ($t_file); zip_close ($zip);
	}

	$dat	= xml_to_arr ($data_xml);

	// FILENAME
	$title		= basename ($file);

	// PREVIEW IMAGE
	// We need to base64-encode "IMAGE100.PNG" to display it
	$img		= base64_encode ($data_png);

	// LXF NAME
	// Usually updated from the filename of the LXF whenever it is saved
	$name		= $dat['@attributes']['name'];

	// PARTS COUNT
	// Gleaned by counting the <brick> nodes in the XML
	$parts		= count ($dat['Bricks']['Brick']);
/*
	// OBJECT COUNT
	// Gleaned by counting the <RigidSystem> nodes in the XML
	echo '<tr><td>Objects</td><td>' . count ($dat['RigidSystems']['RigidSystem']) . '</td></tr>';

	// GROUP COUNT
	// Gleaned by counting the <GroupSystem> nodes in the XML
	echo '<tr><td>Groups</td><td>' . count ($dat['GroupSystems']['GroupSystem']) . '</td></tr>';
*/
	// LDD VERSION
	$version	= $dat['Meta']['Application']['@attributes']['versionMajor'] . '.' . $dat['Meta']['Application']['@attributes']['versionMinor'] . ' (' . $dat['Meta']['Brand']['@attributes']['name'] . ')';

	// BRICKSET VERSION
	$brickset	= $dat['Meta']['BrickSet']['@attributes']['version'];

	$content	.= get_template ('TPL_LXF');
}

echo get_template ('TPL__SHELL');


////////////////////////////////////////////////////////////////////////////////


function xml_to_arr ($what_xml)
{
	$xml	= (file_exists ($what_xml) )
	? simplexml_load_file ($what_xml)
	: simplexml_load_string ($what_xml);

	return (json_decode (json_encode ($xml), true) );
}

function get_template ($what_tpl)
{
	// Get template from constant
	if ($this_tpl = @constant ($what_tpl) )
	{
		/*
		To define a template, use this method

		define ('TPL_NAME_HERE',
		<<<_TEMPLATE
		...
		_TEMPLATE
		);

		*/
		$get_from	= $what_tpl;
	}
	else
	{
		// If template is missing
		@error ('Cannot find template <b>' . $what_tpl . '</b>', (strpos ($what_tpl, '__') ) ? E_USER_ERROR : E_USER_WARNING);
	}

	if ($get_from)
	{
		// Extract all strings from the template which match the {pattern}
		preg_match_all ('/(\{[[:alnum:]_\[\]]*\})/si', $this_tpl, $scan_things);

		foreach ($scan_things[0] as $null => $expected_name)
		{
			$expected_name	= str_replace ('{', '', $expected_name);
			$expected_name	= str_replace ('}', '', $expected_name);

			$search			= '{' . $expected_name . '}';

			// Check if this a template for a PREG replacement string
			if (is_numeric ($expected_name) )
			{
				$replace	= '$' . $expected_name;
				$this_tpl	= @str_replace ($search, $replace, $this_tpl);
			}
			else
			{
				// Determine if this thing is an array
				$expected_temp	= preg_replace ('/([[:alnum:]_]*)(\[)([[:alnum:]_]*)(\])/i', '\\1|\\3', $expected_name);

				@list ($expected_array, $expected_keys)	= explode ('|', $expected_temp);

				global $$expected_name, $$expected_array;

				// Expected value is a constant
				if (defined ($expected_name) )
				{
					$this_tpl	= str_replace ($search, constant ($expected_name), $this_tpl);
				}

				// Expected value is a variable; perhaps even an array!
				else if (isset ($$expected_name) || is_array ($$expected_array) )
				{
					$replace	= '$' . $expected_name;

					if (is_array ($$expected_array) && $$expected_name !== false)
					{
						$expected_name	= $expected_array . '[' . $expected_keys . ']';

						if (!array_key_exists ($expected_keys, $$expected_array) ) { continue; }
					}

					// Strip array key from $expected_name
					if (preg_match ('/(\[)([[:alnum:]_]*)(\])/i', $expected_name, $match) )
					{
						$expected_name	= preg_replace ('/(\[[[:alnum:]_]*\])/i', '', $expected_name);
					}

					$replace	= $$expected_name;

					// Handle array key
					if ($match) { $replace	= $replace[$match[2]]; }

					$this_tpl	= @str_replace ($search, $replace, $this_tpl);
				}
				else
				{
					// Debugging / cleanup for missing constants and variables
					if (defined ('SET_DEBUG') && !SET_DEBUG)
					{
						$this_tpl	= str_replace ('{' . $expected_name . '}', '', $this_tpl);
					}

					// Expected value is missing
					if (defined ('SET_DEBUG') && SET_DEBUG > 1)
					{
						@error ('Cannot find <b>' . $expected_name . '</b>', E_USER_NOTICE);
					}
				}
			}
		}

		return ($this_tpl);
	}
}

function error ($message, $level = E_USER_NOTICE)
{
	$caller	= next (debug_backtrace () );

	if ($caller['function'])
	{
		$message	.= ' for <b>' . $caller['function'] . '()</b>';
	}

	if ($caller['file'] && $caller['line'])
	{
		$message	.= ' in <b>' . $caller['file'] . '</b> on line <b>' . $caller['line'] . '</b>';
		$message	.= "\n<br />\n<br />";
	}

	switch ($level)
	{
		// E_USER_DEPRECATED
		case 16384: echo ('<b>Deprecated</b>: ' . $message); break;
		// E_USER_NOTICE
		case 1024: echo ('<b>Notice</b>: ' . $message); break;
		// E_USER_WARNING
		case 512: echo ('<b>Warning</b>: ' . $message); break;
		// E_USER_ERROR
		case 256: die ('<b>Fatal error</b>: ' . $message); break;
		default: die ('<b>Fatal error</b>: Something went wrong!'); break;
	}
}

?>
