<?php
/**
* Changes from php.mo:
* supress the error if there's no file
* fixed "fuzzy flag first line" bug which didn't saved previous proper string at all
* fix the warning if list finds no $data
* added case for commented unused string
* proper handling of msgctxt
* better storing of same msgid
* corrected data structure for correct counting of plural msgstr
* don't add last translation if it's fuzzy
* removed unedeed phpmo_convert and phpmo_write_mo_file
* more info on https://bugs.mageia.org/show_bug.cgi?id=14899
* added option for passing translation directly as an array
* changed structure of resulting array
* 
* it returns array of translations:
* $dictionary = phpmo_parse_po_file('input.po');
*
* $dictionary = array (
*	'' => array (
*		0 => array (
*			0 => 'Project-Id-Version: ...',
*		),
*	),
*	'msgid string for translation 1' => array ( // msgid
*		0 => array (
*			0 => 'translated string 1', // msgstr
*		),
*	),
*	'msgid string for translation 2' => array ( // msgid
*		0 => array (
*			0 => 'translated string 2', // msgstr
*		),
*		'context explanation for msgstr[1]' => array (   // msgctxt
*			0 => 'translated string 2 but different context', // msgstr
*		),
*		'context explanation for msgstr[2]' => array ( // msgctxt
*			0 => 'another translated string 2 with different context', // msgstr
*		),
*	),
*	'msgid string for translation 3' => array ( // msgid
*		0 => array (
*			'msgid_plural' => 'plural string for translation 3', // msgid_plural
*			0 => 'translated string 3 for nplurals 0', // msgstr[0]
*			1 => 'translated string 3 for nplurals 1', // msgstr[1]
*			2 => 'translated string 3 for nplurals 2', // msgstr[2]
*		),
*	),
*	'msgid string for translation 4' => array ( 			 // msgid
*		'context explanation for msgstr[0]' => array ( 		 // msgctxt
*			'msgid_plural' => 'plural string for translation 4', // msgid_plural
*			0 => 'translated string 4 for nplurals 0',		 // msgstr[0]
*			1 => 'translated string 4 for nplurals 1',		 // msgstr[1]
*			2 => 'translated string 4 for nplurals 2',		 // msgstr[2]
*		),
*	),
* );
*
****************************************************************************************
*
* based on php.mo 0.1 by Joss Crowcroft (http://www.josscrowcroft.com)
* which is
* Based on php-msgfmt by Matthias Bauer (Copyright © 2007), a command-line PHP tool
* for converting .po files to .mo.
* (http://wordpress-soc-2007.googlecode.com/svn/trunk/moeffju/php-msgfmt/msgfmt.php)
*
* License: GPL v3 http://www.opensource.org/licenses/gpl-3.0.html
*/

function phpmo_clean_helper($x) {
	if (is_array($x)) {
		foreach ($x as $k => $v) {
			$x[$k] = phpmo_clean_helper($v);
		}
	} else {
		if ($x[0] == '"')
			$x = substr($x, 1, -1);
		$x = str_replace("\"\n\"", '', $x);
		$x = str_replace('$', '\\$', $x);
	}
	return $x;
}

/* Parse gettext .po files. */
/* @link http://www.gnu.org/software/gettext/manual/gettext.html#PO-Files */
function phpmo_parse_po_file($in, $translation_in_file = true) {
	if ($translation_in_file === true) {
		// read .po file
		$fh = @fopen($in, 'r');
		if ($fh === false) {
			// Could not open file resource
			return false;
		}
	} else {
		if (!is_array($in) || empty($in)) {
			// given translation not valid
			return false;
		}
		$translation_in_file = false;
	}

	// results array
	$hash = array ();
	// temporary array
	$temp = array ();
	// state
	$state = null;
	$fuzzy = false;
	$parse_condition = true;

	// iterate over lines
	while($parse_condition) {
	// output and test line for translation in file
	if ($translation_in_file) {
		if (($line = fgets($fh, 65536)) === false) {
			$parse_condition = false;
			continue;
		}
	// output and test line for translation in array
	} else {
		$line = current($in);
		$end_array_test = next($in);
		if (false === $end_array_test) {
			$parse_condition = false;
			continue;
		}
	}
		$line = trim($line);
		if ($line === '')
			continue;

		$array_of_splited_string = preg_split('/\s/', $line, 2);
		$key = $array_of_splited_string[0];
		$data = (isset($array_of_splited_string[1]) ? $array_of_splited_string[1] : '');
		switch ($key) {
			case '#,' : // flag...
			case '#'  : // translator-comments
			case '#.' : // extracted-comments
			case '#:' : // reference...
			case '#|' : // msgid previous-untranslated-string
			case '#~' : // commented-unused-string
				// start a new entry
				if (sizeof($temp) && array_key_exists('msgid', $temp) && array_key_exists('msgstr', $temp)) {
					if (!$fuzzy)
						$hash[] = $temp;
					$temp = array ();
					$state = null;
					$fuzzy = false;
				}
				if ($key == '#,') 
					$fuzzy = in_array('fuzzy', preg_split('/,\s*/', $data));
				break;
			case 'msgctxt' :
				// context
			case 'msgid' :
				// untranslated-string
			case 'msgid_plural' :
				// untranslated-string-plural
				$state = $key;
				// store previous entry if it exists
				if (sizeof($temp) && array_key_exists('msgid', $temp) && array_key_exists('msgstr', $temp)) {
					if (!$fuzzy)
						$hash[] = $temp;
					$temp = array ();
					$fuzzy = false;
				}
				if ($key == 'msgctxt') {
						if (array_key_exists('msgstr', $temp)) {
							$msgctxt_index = count($temp['msgstr']);
						} else {
							$msgctxt_index = 0;
						}
						$temp['msgctxt'][$msgctxt_index] = $data;
				} else {
					$temp[$state] = $data;
				}
				break;
			case 'msgstr' :
				// translated-string
				$state = 'msgstr';
				$temp[$state][] = $data;
				break;
			default :
				if (strpos($key, 'msgstr[') !== FALSE) {
					// translated-string-case-n
					$state = 'msgstr';
					$temp[$state][] = $data;
				} else {
					// continued lines
					switch ($state) {
						case 'msgid' :
						case 'msgid_plural' :
							$temp[$state] .= "\n" . $line;
							break;
						case 'msgctxt' :
						case 'msgstr' :
							$temp[$state][sizeof($temp[$state]) - 1] .= "\n" . $line;
							break;
						default :
							// parse error
							if ($translation_in_file) {
								fclose($fh);
							}
							return FALSE;
					}
				}
				break;
		}
	}
	if ($translation_in_file) {
		fclose($fh);
	}

	// add final entry
	if ($state == 'msgstr')
		if (!$fuzzy)
			$hash[] = $temp;

	// Cleanup data, merge multiline entries, reindex hash for ksort
	$temp = $hash;
	$hash = array ();
	foreach ($temp as $entry) {
		foreach ($entry as & $v) {
			$v = phpmo_clean_helper($v);
			if ($v === FALSE) {
				// parse error
				return FALSE;
			}
		}

		// add msgctxt if present
		$msgctxt = (array_key_exists('msgctxt', $entry) ? $entry['msgctxt'][0] : 0);
		// and also msgid_plural
		if (array_key_exists('msgid_plural', $entry)) {
			$entry['msgstr']['msgid_plural'] = $entry['msgid_plural'];
		}
		$hash[$entry['msgid']][$msgctxt] = $entry['msgstr'];
	}
	return $hash;
}