<?php

/*******************************************************************************

 WINBINDER - The native Windows binding for PHP for PHP

 Copyright © Hypervisual - see LICENSE.TXT for details
 Author: Rubem Pechansky (http://winbinder.org/contact.php)

 Tool for building WinBinder snapshots and releases

********************************************************************************

Tasks performed:

- Update version number in Source\wb\wb_version.h
- Compile projects if not up-to-date
- Save version number to version.h
- Copy TextPad syntax definition file to WinBinder folder
- Copy text and source code files to web site folder
- Convert HTML files to HTML Help (inserts code for HTML Help keywords)
- Generate manual.chm
- Generate todo_items.html from ToDo application
- Include release notes
- Generate package.xml and package2.xml for PECL
- Save current files to zip file
- Convert .zip to .tar.gz and rename it to .tgz for PECL
- Update version data in setup script
- Force DEBUG = False in setup script
- Force compression in setup script
- Compile Setup application

To do's:

- Config file make_release.ini is not always placed in the same path as make_release.phpw
- Fetch updated mirror list from SourceForge and change wb_install.pas accordingly
- Generate toc.hhc automatically from index.html
- Update date and version instead of just reporting differences via message box
- Update file desc.txt in server
- Upload zip and setup files to server
- Upload web site changes to server
- Keep track of previous releases (history) using a database

*/

//----------------------------------------------------------- CURRENT PARAMETERS

define("VERSION",			"0.61");			// Version of this utility
define("PROJ_STATE",		"alpha");			// For PECL: WinBinder status

//------------------------------------------------------------ SYSTEM PARAMETERS

define("PATH_SCRIPT",	dirname(__FILE__) . "/");
define("PATH_DATA",		PATH_SCRIPT);
define("PATH_INC",		PATH_SCRIPT . "../include/");
define("PATH_RES",		PATH_SCRIPT . "../resources/");
define("PGMFILES",		wb_get_system_info("pgmpath"));

//----------------------------------------------------------------- DEPENDENCIES

include PATH_INC . "winbinder.php";
include PATH_INC . "db\\db_common.inc.php";

//-------------------------------------------------------------- USER PARAMETERS

// Set the constants below according to your system

define("WEBSITE_PATH",		"C:\\@trab\\hypervisual\\website\\pages\\winbinder\\");
define("TARGET_PATH",		"C:\\@desenv\\WinBinder\\@privado\\arquivo\\");
define("ZIPAPP",			"C:\\Util\\Info-zip\\zip\zip.exe");
define("COMPILER_MAKE",		"C:\\Util\\lcc\\bin\\make.exe");
define("TARGZ",				"\"" . PGMFILES . "izarc\izarc.exe\" -cv %s");
define("HELPWORKSHOP", 		"\"" . PGMFILES . "HTML Help Workshop\\hhc.exe\" ");
define("SETUPCOMP", 		"\"" . PGMFILES . "Inno Setup\\compil32.exe\" /cc ");

//-------------------------------------------------------------- OTHER CONSTANTS

define("FLIST",				"filelist.txt");
define("TODO_DATABASE",		"todo");
define("SYS_INIFILE",		"make_release.ini");
define("WB_ROOT",			realpath("..\\..") . "\\");	// The mother of all directories
define("SCRIPTPATH",		dirname(__FILE__) . "\\");
define("ZIPCMD",			WB_ROOT . "tools\\info-zip\\cmd.php");
define("TODO_IO",			WB_ROOT . "phpcode/todo/todo_import_export.inc.php");
define("HELP_DIR",	 		WB_ROOT . "tools\\html_help\\");
define("SOURCE_PATH",		WB_ROOT . "csource\\");
define("VERSION_FILE",		WB_ROOT . "csource\\core\\wb\\wb_version.h");
define("MANUAL_SRC", 		WB_ROOT . "docs\manual");
define("RELNOTES", 			WB_ROOT . "docs\\release_notes.txt");
define("LOGFILE",			WB_ROOT . "docs\\changelog.txt");
define("DLL4",				WB_ROOT . "binaries\\php4\\ext\\php_winbinder.dll");
define("DLL50",				WB_ROOT . "binaries\\php50\\ext\\php_winbinder.dll");
define("DLL51",				WB_ROOT . "binaries\\php51\\ext\\php_winbinder.dll");
define("PEAR10_PACKAGE",	WB_ROOT . "package.xml");
define("PEAR14_PACKAGE",	WB_ROOT . "package2.xml");
define("TODO_PATH",			WB_ROOT . "phpcode\\todo\\");
define("EXAMPLE_PATH",		WB_ROOT . "phpcode\\examples\\");
define("WB_TOOLS",			WB_ROOT . "tools\\");
define("SETUPSCRIPT", 		WB_TOOLS . "inno_setup\\wb_setup.iss");
define("SETUPCODE", 		WB_TOOLS . "inno_setup\\wb_setup.pas");
define("WEB_TODO_HTML",		WEBSITE_PATH . "doc\\todo_items.html");
define("MANUAL_TGT", 		HELP_DIR . "manual");
define("HELP_PROJECT",		HELP_DIR . "manual.hhp");
define("FILELIST",			SCRIPTPATH . FLIST);
define("PEAR10_TEMPLATE",	SCRIPTPATH . "pear10_template.xml");
define("PEAR14_TEMPLATE",	SCRIPTPATH . "pear14_template.xml");

define("APPNAME", 			"WinBinder Release Maker");	// Application name
define("VERSION_CONTENTS",	"\r\n// Current WinBinder version\r\n// This file is generated automatically by " . APPNAME . ".\r\n\r\n#define WINBINDER_VERSION\t\t\"%s\"\r\n#define WB_MAJ\t\t%d\r\n#define WB_MIN\t\t%d\r\n#define WB_REL\t\t%d\r\n");
define("COMBO_ITEMS",		"No action\nSnapshot\nPHP developer\nC developer\nRelease\nMinimal PHP 4\nMinimal PHP 5\nDLLs only");

//-------------------------------------------------------------------- VARIABLES

// Various arrays

$flistfiles = array("", "snapshot", "php_develop", "c_develop", "release", "php4", "php5", "dlls");
$ftemplate = array("", "wb_snapshot_%d.zip", "wb_php_devel_%s.zip", "wb_c_devel_%s.zip", "winbinder_%s.zip", "php4_minimal.zip", "php5_minimal.zip", "wb_dll_%s.zip");
$all_flags = array("CHM","COPYFILES","EXPORTTODO","ZIP","CHECKDLLS","XML","TGZ","MIME","RELNOTES", "SETUP");
$all_ctrls = $all_flags;
array_push($all_ctrls, "TYPE", "VERBOSE");
$zip_dependent = array("CHECKDLLS","XML","TGZ","MIME", "FLIST");

// Additional files to copy

$copies = array(

	PGMFILES . "TextPad\\Samples\\php_winbinder.syn",		WB_ROOT . "Tools\\textpad\\php_winbinder.syn",

	WB_ROOT . "readme.txt",									WEBSITE_PATH . "doc\\readme.txt",
	WB_ROOT . "docs\\changelog.txt",						WEBSITE_PATH . "doc\\changelog.txt",
	WB_ROOT . "docs\\release_notes.txt",					WEBSITE_PATH . "doc\\release_notes.txt",
	WB_ROOT . "docs\\license.txt",							WEBSITE_PATH . "doc\\license.txt",
	WB_ROOT . "phpcode\\make_release\\make_release.phpw",	WEBSITE_PATH . "code\\make_release.phpw",
	WB_ROOT . "phpcode\\make_release\\make_release.rc",		WEBSITE_PATH . "code\\make_release.rc",

	EXAMPLE_PATH . "minimal.phpw",							WEBSITE_PATH . "code\\minimal.phpw",
	EXAMPLE_PATH . "digiclock.phpw",						WEBSITE_PATH . "code\\digiclock.phpw",
	EXAMPLE_PATH . "hello.phpw",							WEBSITE_PATH . "code\\hello.phpw",
//	EXAMPLE_PATH . "hello_oo.phpw",							WEBSITE_PATH . "code\\hello_oo.phpw",
	EXAMPLE_PATH . "calc.phpw",								WEBSITE_PATH . "code\\calc.phpw",
	EXAMPLE_PATH . "ttfreader.phpw",						WEBSITE_PATH . "code\\ttfreader.phpw",
	EXAMPLE_PATH . "borderless.phpw",						WEBSITE_PATH . "code\\borderless.phpw",
	EXAMPLE_PATH . "calc.rc",								WEBSITE_PATH . "code\\calc.rc",
);

//-------------------------------------------------------------- EXECUTABLE CODE

// Create main window

// Remove the line below while not under development

file_put_contents("make_release.rc.php", "<?php\n\n" . parse_rc(file_get_contents("make_release.rc"),
  '$mainwin', null, 'ModelessDialog', null, WBC_CENTER, WBC_CENTER, WBC_CENTER, WBC_CENTER,
  'WBC_INVISIBLE', 0) . "\n?>");

// More includes

include ZIPCMD;
include TODO_IO;
include "make_release.rc.php";

wb_set_handler($mainwin, "process_main");
wb_set_text($mainwin, APPNAME . " version " . VERSION);
wb_set_image($mainwin, PATH_RES . "hyper.ico");

// Initialize controls

wb_set_text(wb_get_control($mainwin, IDC_TYPE), COMBO_ITEMS);
wb_set_text(wb_get_control($mainwin, IDC_NOTES), file_get_contents(RELNOTES));

// Accelerator table

wb_create_control($mainwin, Accel, array(
	array(IDC_GO,	"F9"),
));

// Read data from INI file

$lastresult = "";//"(Output)";
$settings = parse_ini(@file_get_contents(SYS_INIFILE));
$allctrls = $all_ctrls;

if($settings) {
	foreach($all_ctrls as $flag) {
		$ctrl = wb_get_control($mainwin, constant("IDC_" . $flag));
		$status = @$settings["Settings"][strtolower($flag)];
		if(wb_get_class($ctrl) == ComboBox)
			wb_set_selected($ctrl, $status);
		else
			wb_set_value($ctrl, $status);
	}
} else {
	// Using this app for the first time
	process_main($mainwin, IDC_TYPE);
}
process_main($mainwin, IDC_ZIP);		// Disable commands if it is the case
process_main($mainwin, IDC_RELNOTES);	// Disable commands if it is the case

// Get version from C header file

$current_version = @file_get_contents(VERSION_FILE);
$def = preg_match("/WINBINDER_VERSION\s+\"(.[^\"]*)\"/", $current_version, $ver);
$ver = @$ver[1];
wb_set_text(wb_get_control($mainwin, IDC_VERSION), $ver);
$textbox = wb_get_control($mainwin, IDC_RESULT);

wb_set_text(wb_get_control($mainwin, IDC_STATE), PROJ_STATE);

// Move and show main window

$xpos = @$settings["Settings"]["xpos"];
$ypos = @$settings["Settings"]["ypos"];
wb_set_focus(wb_get_control($mainwin, IDC_GO));
wb_set_position($mainwin, $xpos, $ypos);
wb_set_visible($mainwin, true);

check_date_version($mainwin, LOGFILE, $ver);

// Enter application loop

wb_main_loop();

//--------------------------------------------------------------- MAIN FUNCTIONS

/* Process main window commands */

function process_main($window, $id)
{
	global $flistfiles, $all_flags, $zip_dependent, $lastresult, $textbox;

	switch($id) {

		case IDC_RELNOTES:
			$status = wb_get_value(wb_get_control($window, $id));
			wb_set_enabled(wb_get_control($window, IDC_NOTES), $status);
			break;

		case IDC_SAVERELEASE:
			if(save_version($window))
				out("Done.\n");
			break;

		case IDC_ZIP:
			$status = wb_get_value(wb_get_control($window, $id));
			foreach($zip_dependent  as $flag)
				wb_set_enabled(wb_get_control($window, constant("IDC_" . $flag)), $status);
			if(wb_get_value(wb_get_control($window, $id))) {
				$fname = $flistfiles[wb_get_selected(wb_get_control($window, IDC_TYPE))];
				wb_set_text(wb_get_control($window, IDC_FLIST),	$fname ? ($fname . "_zipme.txt") : "(none)");
			} else {
				wb_set_text(wb_get_control($window, IDC_FLIST),	"");
			}
			break;

		case IDC_RESULT:		// Hack to make a white "read-only" text box
			wb_set_text(wb_get_control($window, $id), $lastresult);
			break;

		case IDC_CLEAR:
			out(null);
			break;

		case IDC_TYPE:

			$check = array(
				array(0,0,0,0,0,0,0,0,0,0),		// Do nothing
				array(0,0,0,1,0,0,0,0,0,0),		// Snapshot
				array(0,1,0,1,1,0,0,1,0,0),		// PHP developer build
				array(0,0,0,1,0,0,0,0,0,0),		// C developer
				array(1,1,1,1,1,1,1,0,1,1),		// Release
				array(0,1,0,1,0,0,0,0,0,0),		// Minimal PHP 4
				array(0,1,0,1,0,0,0,0,0,0),		// Minimal PHP 5
				array(0,0,0,1,1,0,0,0,0,0),		// DLL
			);
			$status = wb_get_selected(wb_get_control($window, $id));
			for($i = 0; $i < count($all_flags); $i++) {
				wb_set_value(wb_get_control($window, constant("IDC_" . $all_flags[$i])),
				$check[$status][$i]);
			}
			process_main($window, IDC_ZIP);
			process_main($window, IDC_RELNOTES);
			process_main($window, IDC_COPYFILES);

			//wb_set_enabled(wb_get_control($window, IDC_GO), $status);
			break;

		case IDC_ABOUT:
			wb_message_box($window,  APPNAME . " version: " . VERSION . "\r\nWinBinder version: " .
			  WBC_VERSION . "\r\nPHP version: " . PHP_VERSION, "About " . APPNAME);
			break;

		case IDC_GO:
			go($window);
			break;

		case IDC_SAVEINI:
			save_ini($window);
			break;

		case IDCLOSE:		// IDCLOSE is predefined
			save_ini($window);
			wb_destroy_window($window);
			break;
	}
}

function save_version($mainwin)
{
	global $current_version, $ver;

	// Get version number from edit control and save wb_version.h with new version number

	$current_version = @file_get_contents(VERSION_FILE);
	$ver = trim(wb_get_text(wb_get_control($mainwin, IDC_VERSION)));
	preg_match("/(\d+)\.(\d+)\.(\d+)/", $ver, $parts);
	$new_version = sprintf(VERSION_CONTENTS, $ver, $parts[1], $parts[2], $parts[3]);
	if(preg_split("/\r\n/", $current_version) != preg_split("/\r\n/", $new_version)) {
		out("Updating project version number to $ver...\r\n");
		file_put_contents(VERSION_FILE, $new_version);
		return TRUE;
	} else
		return FALSE;
}

/* Do various actions according to options */

function go($mainwin)
{
	global $copies, $verbose, $current_version, $ver, $flistfiles, $ftemplate;

	// Get some flags from the interface

	$verbose = wb_get_value(wb_get_control($mainwin, IDC_VERBOSE));
	$type = wb_get_selected(wb_get_control($mainwin, IDC_TYPE));

	// Get version number from edit control and save wb_version.h with new version number

	save_version($mainwin);

	// Verify changelog date / version

	if(!check_date_version($mainwin, LOGFILE, $ver)) {
		out("Aborted.\r\n");
		return;
	}

	// Start

	out(null);
	out("Working...\r\n");

/*
	$ver = trim(wb_get_text(wb_get_control($mainwin, IDC_VERSION)));
	$new_version = sprintf(VERSION_CONTENTS, $ver);
	if(preg_split("/\r\n/", $current_version) != preg_split("/\r\n/", $new_version)) {
		out("Updating project version number...\r\n");
		file_put_contents(VERSION_FILE, $new_version);
	}*/

	// Save release notes

	if(wb_get_value(wb_get_control($mainwin, IDC_RELNOTES))) {

		if(file_get_contents(RELNOTES) != wb_get_text(wb_get_control($mainwin, IDC_NOTES))) {
			out("Saving release notes...\r\n");
			file_put_contents(RELNOTES, wb_get_text(wb_get_control($mainwin, IDC_NOTES)));
		}
	}

	// Change directory

	$currdir = getcwd();
	chdir(WB_ROOT);

	// Delete zip file if it exists

	if(wb_get_value(wb_get_control($mainwin, IDC_ZIP))) {

		if(strstr($ftemplate[$type], '%d')) {
			$fmt = str_replace('%d', '%s', $ftemplate[$type]);
			$filename = TARGET_PATH . sprintf($fmt, date('ymd'));
		} else
			$filename = TARGET_PATH . sprintf($ftemplate[$type], str_replace("-dev", "", $ver));

		if(file_exists($filename)) {
			if(!wb_message_box($mainwin, "Overwrite " . basename($filename) . "?", APPNAME, WBC_YESNO)) {
				out("Aborted.\r\n");
				chdir($currdir);
				return;
			}
			unlink($filename);
		}
	}

	// Compile project and update some files

	if(wb_get_value(wb_get_control($mainwin, IDC_ZIP))) {

		// Check and update DLLs

		if(wb_get_value(wb_get_control($mainwin, IDC_CHECKDLLS))) {

			if(needs_updating(DLL4, SOURCE_PATH)) {
				// Cannot overwrite php_winbinder.dll, It's being used right now!
				wb_message_box($mainwin, "Warning: The WinBinder DLL for PHP 4 is not up-to-date. Please recompile it and try again.", APPNAME, WBC_WARNING);
				out("Aborted.\r\n");
				return;
			}

			if(needs_updating(DLL50, SOURCE_PATH)) {
				wb_message_box($mainwin, "Warning: The WinBinder DLL for PHP 5.0 is not up-to-date. Please recompile it and try again.", APPNAME, WBC_WARNING);
				out("Aborted.\r\n");
				return;
			}

			if(needs_updating(DLL51, SOURCE_PATH)) {
				wb_message_box($mainwin, "Warning: The WinBinder DLL for PHP 5.1 is not up-to-date. Please recompile it and try again.", APPNAME, WBC_WARNING);
				out("Aborted.\r\n");
				return;
			}
		}

		// Build package.xml (2 versions)

		if(wb_get_value(wb_get_control($mainwin, IDC_XML))) {
			out("Creating PEAR 1.0 information...\r\n");
			update_xml_10($ver);
			out("Creating PEAR 1.4 information...\r\n");
			update_xml_14($ver);
		}
	}

	// Convert HTML files to HTML help format

	if(wb_get_value(wb_get_control($mainwin, IDC_CHM))) {

		out("Converting HTML files to HTML Help...");
		$helpfiles = get_folder_files(MANUAL_SRC, TRUE, TRUE, "/.*\.(html?|css|jpe?g|gif|[pm]ng)$/i");
		if($verbose)
			out("\r\n");

		empty_folder_files(MANUAL_TGT);	// Avoid obsolete files from manual folder

		// Populate manual folder with fresh files

		foreach($helpfiles as $srcfile) {
			$tgtfile = str_replace(MANUAL_SRC, MANUAL_TGT, $srcfile);

			// Create directory if it does not exist

			$dir = dirname($tgtfile);
			if(!file_exists($dir))
				mkdir($dir);

			if(strstr($srcfile, ".htm")) {
				$html = file_get_contents($srcfile);
				$hasklinks = preg_match("/<!--KW:(.*)-->/is", $html, $klinks);
				if($hasklinks) {		// Create "object" tag
					$lines = preg_split("/[\r\n]/", $klinks[1]);
					$klinks = "";
					foreach($lines as $line) {
						$line = trim($line);
						if($line)
							$klinks .= "\t<param name=\"Keyword\" value=\"$line\">\r\n";
					}
					$html = preg_replace("/<!--KW:(.*)-->/is",
						"<object type=\"application/x-oleobject\" classid=\"clsid:1e2a7bd0-dab9-11d0-b93a-00c04fc99f9e\">\r\n$klinks</object>", $html);
					if(!file_put_contents($tgtfile, $html))
						out("Warning: Failed to copy file $tgtfile.\r\n");
					if($verbose)
						out("Converting " . basename($tgtfile) . "...\r\n");
				} else {
					copy($srcfile, $tgtfile);
					@touch($tgtfile, filemtime($srcfile));
				}
			} else {
				copy($srcfile, $tgtfile);
				@touch($tgtfile, filemtime($srcfile));
			}
		}
		if(!$verbose)
			out("\r\n");

		// Create HTML help manual

		out("Creating CHM manual...\r\n");
		$res = shell_exec(HELPWORKSHOP . " " . HELP_PROJECT) . "\n";
		if($verbose)
			out($res);
	}

	// Export To Do list as HTML

	if(wb_get_value(wb_get_control($mainwin, IDC_EXPORTTODO))) {
		out("Creating To Do list...\r\n");
		todo_export();
	}

	// Copy/update files

	if(wb_get_value(wb_get_control($mainwin, IDC_COPYFILES))) {

		if(!$verbose)
			out("Copying/updating files...");

		for($i = 0; $i < count($copies); $i += 2) {
			if($verbose)
				out("Copying/updating " . basename($copies[$i + 1]) . "...\r\n");
			else
				out(".");
			$tgtfile = $copies[$i + 1];
			copy($copies[$i], $tgtfile);

			// Remove all references to any e-mail

			file_put_contents($tgtfile, preg_replace("/[\(\<]?\w+@\w+(\.\w{2,3})+[\)\>]?/i", "", file_get_contents($tgtfile)));

			@touch($copies[$i + 1], filemtime($copies[$i]));
		}
		if(!$verbose)
			out("\r\n");
	}

	// Create zip file

	if(wb_get_value(wb_get_control($mainwin, IDC_ZIP))) {
//		if($type == 5 || $type == 6) {
//			$zipper = ZIPPER_FLAT;
//			out("You must remove the file paths manually from inside the ZIP file.\r\n");
//		} else
//			$zipper = ZIPPER;

//		printf($zipper, $filename, $flistfiles[$type], $flistfiles[$type], "");

		out("Creating zip archive...\r\n");
		if($verbose)
			out("\r\n" . shell_exec(sprintf(ZIPPER, $filename, $flistfiles[$type], $flistfiles[$type], "")) . "\r\n");
		else
//			out("\r\n" . exec(sprintf(ZIPPER, $filename, $flistfiles[$type], $flistfiles[$type], "")) . "\r\n");
			exec(sprintf(ZIPPER, $filename, $flistfiles[$type], $flistfiles[$type], ""));

		if(file_exists($filename))
			out("File " . basename($filename)  . " created successfully.\r\n");
		else {
			out("Error creating file $filename.\r\n");
			out("Aborted.\r\n");
			return;
		}

		// Convert zip file to tar.gz

		if(wb_get_value(wb_get_control($mainwin, IDC_TGZ))) {

			out("Converting to tar.gz (may require user intervention)...\r\n");
			$targz = str_replace(".zip", ".tar.gz", $filename);
			$tgz = str_replace(".zip", ".tgz", $filename);

			if($verbose)
				out("\r\n" . shell_exec(sprintf(TARGZ, $filename)) . "\r\n");
			else
				out("\r\n" . exec(sprintf(TARGZ, $filename)) . "\r\n");
			@unlink($tgz);
			@rename($targz, $tgz);
		}

		// MIME-encode zip file

		if(wb_get_value(wb_get_control($mainwin, IDC_MIME))) {

			out("Encoding as MIME...\r\n");
			$mime = str_replace(".zip", ".b64", $filename);
			file_put_contents($mime, b64encode($filename));
		}

	}

	// Create setup

	if(wb_get_value(wb_get_control($mainwin, IDC_SETUP))) {

		out("Compiling setup application...\r\n");

		// Change version number in setup script (.iss) file

		$contents = file_get_contents(SETUPSCRIPT);
		$previous = $contents;
		$contents = preg_replace("/^(AppVerName\s*=).*$/im", "\\1WinBinder version $ver", $contents);
		$contents = preg_replace("/^(VersionInfoVersion\s*=).*$/im", "\${1}" . preg_replace("/[^0-9\.]/", "", $ver), $contents);

		// Force compression settings

		$contents = preg_replace("/^(InternalCompressLevel\s*=).*/im", "\\1normal", $contents);
		$contents = preg_replace("/^(SolidCompression\s*=).*/im", "\\1true", $contents);
		$contents = preg_replace("/^(Compression\s*=).*/im", "\\1lzma/max", $contents);

		// Save .iss file and compile setup

		if($contents != $previous)
			file_put_contents(SETUPSCRIPT, $contents);

		// Force DEBUG = False in Pascal script

		$contents = file_get_contents(SETUPCODE);
		$contents = preg_replace("/WB_DEBUG = True/i", "WB_DEBUG = False", $contents);
		if($contents != $previous)
			file_put_contents(SETUPCODE, $contents);

		// Compile setup

		shell_exec(SETUPCOMP . SETUPSCRIPT);
	}

	// End

	chdir($currdir);
	out("Done.\r\n");
}

//---------------------------------------------------------- AUXILIARY FUNCTIONS

// Extracts last valid version number and date from changelog and compares them to
// current date and version number

function check_date_version($window, $logfile, $ver)
{
	// Assumes that the Date line is always located after the Version line
	// Code adapted from version.php (web site)

	$log = file($logfile);
	$maxlines = 20;		// Give up after 20 lines
	$currlin = 0;

	// Extract "version" line

	$version = "";
	for($i = 0; $i < $maxlines; $i++) {
		$line = trim($log[$i]);
		if(preg_match("/Version/i", $line)) {
			$version = $line;
			$currlin = $i;
			break;
		}
	}

	// Check version

 	$version = preg_replace("/\s*Version\s*/", "", $version);
	$version = preg_replace("/\s*\-\s*build\s*/", ".", $version);
	$version = preg_replace("/\s*\((pre\-)?alpha\)\s*/", "", $version);
	$ver = preg_replace("/\s*-\s*dev/", "", $ver);
	if(trim($version) != trim($ver)) {
		wb_message_box($window, "Warning: The version in the changelog is '$version'. Please edit\nthe changelog or the Version field and try again.", APPNAME, WBC_WARNING);
		return FALSE;
	}

	// Extract "date" line

	$date = "";
	for($i = $currlin; $i < $maxlines; $i++) {
		$line = trim($log[$i]);
		if(preg_match("/Date/i", $line)) {
			$date = $line;
			break;
		}
	}

	// Check date

	if(trim($date) != "Date: " . date("M d, Y")) {
		wb_message_box($window, "Warning: The date in the changelog is incorrect or invalid. Please change it and try again.", APPNAME, WBC_WARNING);
		return FALSE;
	}
	return TRUE;
}

/* Generate file list in PEAR 1.0 XML format */

function update_xml_10($version)
{
	global $mainwin;

	$text = file(FILELIST);
	$files = "";
	foreach($text as $file) {
		$file = strtolower(trim($file));
		$filename = WB_ROOT . $file;
		if(is_file($filename)) {				// Ignore subdirectories
			$md5hash = md5_file($filename);
			$files .= "         <file role=\"src\" md5sum=\"$md5hash\" name=\"$file\"/>\r\n";
		}
	}

	// Replace variables

	$version = str_replace("-dev", "", $version);

	$xml = file_get_contents(PEAR10_TEMPLATE);
	$xml = str_replace("%filelist%", $files, $xml);
	$xml = str_replace("%version%", $version, $xml);
	$xml = str_replace("%date%", date("Y-m-d"), $xml);
	$xml = str_replace("%state%", PROJ_STATE, $xml);
	$xml = str_replace("%notes%", wb_get_text(wb_get_control($mainwin, IDC_NOTES)), $xml);

	// Save XML

	file_put_contents(PEAR10_PACKAGE, $xml);
}

/* Generate file list in PEAR 1.4 XML format. There is some cheating here because
  the new directory structure feature ("<dir name=...>")is not used properly, but if
  PEAR itself can do it (see PEAR package2.xml), so can we */

function update_xml_14($version)
{
	global $mainwin;

	$text = file(FILELIST);
	$files = " <dir name=\"/\">\r\n";
	foreach($text as $file) {
		$file = strtolower(trim($file));
		$filename = WB_ROOT . $file;

		if(is_file($filename)) {				// Ignore subdirectories
			$md5hash = md5_file($filename);
			$parts = pathinfo($filename);
			$role = get_role(@$parts['extension']);
			$files .= "  <file md5sum=\"$md5hash\" name=\"$file\" role=\"$role\" />\r\n";
		}
	}
	$files .= " </dir> <!-- / -->";

	// Replace variables

	$version = str_replace("-dev", "", $version);

	$xml = file_get_contents(PEAR14_TEMPLATE);
	$xml = str_replace("%contents%", $files, $xml);
	$xml = str_replace("%version%", $version, $xml);
	$xml = str_replace("%date%", date("Y-m-d"), $xml);
	$xml = str_replace("%time%", date("H:i:s"), $xml);
	$xml = str_replace("%stability%", PROJ_STATE, $xml);
	$xml = str_replace("%notes%", wb_get_text(wb_get_control($mainwin, IDC_NOTES)), $xml);

	// Save XML

	file_put_contents(PEAR14_PACKAGE, $xml);
}

// Reference: http://www.appelsiini.net/~tuupola/doc/peardoc/developers.packagedef.html

function get_role($extension)
{
	switch($extension) {

		case 'txt':
		case 'ini':
		case 'prj':
		case 'wap':
		case 'wej':
		case 'xml':
		case 'html':
		case 'css':
		case 'chm':
			$role = 'doc';
			break;

		case 'php':
		case 'phpw':
			$role = 'php';
			break;

		case '':			// "makefile"
		case 'c':
		case 'h':
		case 'rc':
			$role = 'src';
			break;

		case 'bmp':
		case 'gif':
		case 'png':
		case 'jpg':
			$role = 'data';
			break;

		default:
			$role = 'unkwnown';
			break;
	}
	return $role;
}

// Reference: http://forums.devshed.com/archive/t-125668

function b64encode($filename)
{
	$contents = file_get_contents($filename);
	$filename = basename($filename);
	$contents = chunk_split(base64_encode($contents));
	return "Content-Type: application/octetstream;\n\tname=$filename\nContent-Transfer-Encoding: base64\n" .
	"Content-Disposition: attachment;\n\tfilename=$filename\n\n$contents\n\n--end\r\n";
}

function out($str)
{
	global $mainwin, $textbox, $lastresult;

	if($str === NULL) {
		$lastresult = "";
		wb_set_text($textbox, "");
		wb_refresh($textbox, 1);
		return;
	}

	if(!$str) {
		$lastresult = "";
		return;
	}

	$lastresult .= $str;
	wb_set_text($textbox, $lastresult);
	wb_refresh($textbox, 1);
}

// Rough test to see if $targetfile needs to be rebuilt

function needs_updating($targetfile, $path)
{
	// Correct path name

	$comp = filemtime($targetfile);

	$path = str_replace('/', '\\', $path);
	if(substr($path, -1) != '\\')
		$path .= "\\";
	if(!$path || !@is_dir($path))
		return array();

	// Browse the subdiretory list recursively

	$dir = array();
	if($handle = opendir($path)) {
		while(($file = readdir($handle)) !== false) {
			if(!is_dir($path.$file)) {		// No directories / subdirectories
				if($comp < filemtime($path.$file))
					return TRUE;
			} else if($file[0] != ".") {	// Exclude "." and ".."
				if(needs_updating($targetfile, $path.$file))
					return TRUE;
			}
		}
	}
	closedir($handle);
	return FALSE;
}

// A recursive function for flattening nested arrays
// From http://php.net/array

function flatten_array($array)
{
	$flat_array = array();
	for($x = 0; $x < sizeof($array); $x++) {
		$element = $array[$x];
		if(is_array($element)) {
			$results = flatten_array($element);
			for($y = 0; $y < sizeof($results); $y++) {
				$flat_array[] = $results[$y];
			}
		} else {
			$flat_array[] = $element;
		}
	}
	return $flat_array;
}

// Empties folders recursively

function empty_folder_files($path, $mask="")
{
	$files = flatten_array(get_folder_files($path, true, true, ""));

	foreach($files as $file)
		unlink($file);
}

// Exports To Do list as HTML

function todo_export()
{
	db_open_database(TODO_DATABASE, TODO_PATH);
	$filename = WEB_TODO_HTML;
	$data = db_get_data("item", null, "", "priority != 4",
		FETCH_NUM, "id", "name");		// Exclude "solved" items
	$html = todo_export_html($data);
	file_put_contents($filename, $html);
	db_close_database();
}

// Save the make_release configuration file

function save_ini($window)
{
	global $settings, $allctrls;

	out(null);
	out("Saving configurations...\r\n");

	// Get values

	foreach($allctrls as $flag) {
		$ctrl = wb_get_control($window, constant("IDC_" . $flag));
		if(wb_get_class($ctrl) == ComboBox)
			$settings["Settings"][strtolower($flag)] = wb_get_selected($ctrl);
		else
			$settings["Settings"][strtolower($flag)] = wb_get_value($ctrl);
	}

	$pos = wb_get_position($window);
	$settings["Settings"]["xpos"] = $pos[0];
	$settings["Settings"]["ypos"] = $pos[1];

	// Save options to INI file

	$contents = generate_ini($settings, "; Make Release INI file\r\n");
	if($contents) {
		file_put_contents(SYS_INIFILE, $contents);
	} else
		wb_message_box($window, MSG_FILESAVEERR, APPNAME);
	out("Done.\r\n");
}

//------------------------------------------------------------------ END OF FILE

?>
