<?php
/**
 * This file implements the {@link POFile} and {@link POTFile} classes, used to handle gettext style
 * .PO and .POT files.
 *
 * b2evolution - {@link http://b2evolution.net/}
 * Released under GNU GPL License - {@link http://b2evolution.net/about/license.html}
 * @copyright (c)2003-2007 by Francois PLANQUE - {@link http://fplanque.net/}
 * Parts of this file are copyright (c)2004 by Daniel HAHLER - {@link http://thequod.de/contact}.
 *
 * {@internal Open Source relicensing agreement:
 * Daniel HAHLER grants Francois PLANQUE the right to license
 * Daniel HAHLER's contributions to this file and the b2evolution project
 * under any OSI approved OSS license (http://www.opensource.org/licenses/).
 * }}
 *
 * @package internal
 * @author blueyed: Daniel HAHLER
 */


/**
 * A quick and dirty class for PO/POT files
 *
 * @package internal
 */
class POFile
{
	var $msgids = array();

	function POFile($filename)
	{
		$this->filename = str_replace( '\\', '/', $filename );
	}

	/**
	 * adds a MSGID for a specific source file
	 */
	function addmsgid( $msgid, $sourcefile = '', $trans = '' )
	{
		if( in_array($msgid, array('trans_locale', 'trans_charset', 'trans_available')) )
		{ // don't put those into POT file
			return;
		}

		// replace links
		$msgid = preg_replace('/<a\s+([^>]*)>/', '<a %s>', $msgid);

		// we don't want tabs and returns in the msgid, but we must escape '"'
		$search = array("\r", "\n", "\t", '"');
		$replace = array('', ' ', '', '\"');
		$msgid = str_replace($search, $replace, $msgid);

		if( !isset($this->msgids[ $msgid ]) )
		{
			$this->msgids[ $msgid ] = '';
		}
		if( !empty($sourcefile) )
		{
			$this->msgids[ $msgid ]['source'][] = $sourcefile;
		}
		$this->msgids[ $msgid ]['trans'][] = $trans;
	}

	/**
	 * translates msgid
	 */
	function translate( $msgid )
	{
		$omsgid = $msgid;  // remember

		if( preg_match_all('/<a\s+([^>]*)>/', $msgid, $matches) )
		{ // we have to replace links
			// remember a-tag params
			$aparams = $matches[1];

			// generate clean msgid like in .po files
			$msgid = preg_replace('/<a\s+([^>]*)>/', '<a %s>', $msgid);
		}

		// we don't have formatting in the .po files, but escaped '"'
		$msgid = str_replace( array("\r", "\n", "\t", '"'), array('', ' ', '', '\"'), $msgid);

		if( isset($this->msgids[ $msgid ]) )
		{
			$trans = $this->msgids[ $msgid ]['trans'];

			if( isset($aparams) )
			{
				$trans = vsprintf($trans, $aparams);
			}

			return $trans;
		}
		else
		{
			#pre_dump( $msgid, 'not translated!' );
			return TRANSTAG_OPEN.$omsgid.TRANSTAG_CLOSE;
		}
	}

	/**
	 * reads .po file
	 *
	 * this is quite the same as in locales.php for the extract part.
	 *
	 * @return array with msgids => array( 'trans' => msgstr )
	 */
	function read( $echo_source_info = true )
	{
		$lines = file( $this->filename );
		$lines[] = '';	// Adds a blank line at the end in order to ensure complete handling of the file
		$all = 0;
		$fuzzy = 0;
		$untranslated = 0;
		$translated = 0;
		$status = '-';
		$matches = array();
		$sources = array();
		$loc_vars = array();
		$this->msgids = array();
		$is_fuzzy = false;
		foreach ($lines as $line)
		{
			// echo 'LINE:', $line, '<br />';
			if(trim($line) == '' )
			{	// Blank line, go back to base status:
				if( $status == 't' )
				{	// ** End of a translation **:
					if( $msgstr == '' )
					{
						$untranslated++;
						// echo 'untranslated: ', $msgid, '<br />';
					}
					elseif( $is_fuzzy )
					{
						$fuzzy++;
						// echo 'fuzzy: ', $msgid, "<br />\n";
					}
					else
					{
						$translated++;

						// Inspect where the string is used
						$sources = array_unique( $sources );
						// echo '<p>sources: ', implode( ', ', $sources ), '</p>';
						foreach( $sources as $source )
						{
							if( !isset( $loc_vars[$source]  ) ) $loc_vars[$source] = 1;
							else $loc_vars[$source] ++;
						}

						// Save the string
						// $ttrans[] = "\n\t'".str_replace( "'", "\'", str_replace( '\"', '"', $msgid ))."' => '".str_replace( "'", "\'", str_replace( '\"', '"', $msgstr ))."',";
						// $ttrans[] = "\n\t\"$msgid\" => \"$msgstr\",";
						#$ttrans[] = "\n\t'".str_replace( "'", "\'", str_replace( '\"', '"', $msgid ))."' => \"".str_replace( '$', '\$', $msgstr)."\",";
						$this->msgids[$msgid]['trans']
							= str_replace( array('\t', '\r', '\n', '\"'), array("\t", "\r", "\n", '"'), $msgstr);

					}
				}
				$status = '-';
				$msgid = '';
				$msgstr = '';
				$sources = array();
				$is_fuzzy = false;
			}
			elseif( ($status=='-') && preg_match( '#^msgid "(.*)"#', $line, $matches))
			{	// Encountered an original text
				$status = 'o';
				$msgid = $matches[1];
				// echo 'original: "', $msgid, '"<br />';
				$all++;
			}
			elseif( ($status=='o') && preg_match( '#^msgstr "(.*)"#', $line, $matches))
			{	// Encountered a translated text
				$status = 't';
				$msgstr = $matches[1];
				// echo 'translated: "', $msgstr, '"<br />';
			}
			elseif( preg_match( '#^"(.*)"#', $line, $matches))
			{	// Encountered a followup line
				if ($status=='o')
					$msgid .= $matches[1];
				elseif ($status=='t')
					$msgstr .= $matches[1];
			}
			elseif( ($status=='-') && preg_match( '@^#:(.*)@', $line, $matches))
			{	// Encountered a source code location comment
				// echo $matches[0],'<br />';
				$sourcefiles = preg_replace( '@\\\\@', '/', $matches[1] );
				// $c = preg_match_all( '@ ../../../([^:]*):@', $sourcefiles, $matches);
				$c = preg_match_all( '@ ../../../([^/:]*)@', $sourcefiles, $matches);
				for( $i = 0; $i < $c; $i++ )
				{
					$sources[] = $matches[1][$i];
				}
				// echo '<br />';
			}
			elseif(strpos($line,'#, fuzzy') === 0)
			{
				$is_fuzzy = true;
			}
		}

		if( $echo_source_info )
		{
			ksort( $loc_vars );
			foreach( $loc_vars as $source => $c )
			{
				echo $source, ' = ', $c, '<br />';
			}
		}

		return( $this->msgids );
	}
}


/**
 * A class build upon class POFile to provide specific POT actions (write)
 *
 * @package internal
 */
class POTFile extends POFile
{
	/**
	 * @return boolean
	 */
	function write()
	{
		global $targets, $locales;

		log_('Writing POTFile '.$this->filename.'..');
		$fh = @fopen( $this->filename, 'w' );
		if( ! $fh )
		{
			log_( sprintf('<p class="error">Could not open %s for writing.</p>', $this->filename) );
			return false;
		}
		fwrite($fh, '# SOME DESCRIPTIVE TITLE.'."\n"
			.'# Copyright (C) YEAR Francois PLANQUE'."\n"
			.'# This file is distributed under the same license as the PACKAGE package.'."\n"
			.'# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.'."\n"
			.'#'."\n"
			.'#, fuzzy'."\n"
			.'msgid ""'."\n"
			.'msgstr ""'."\n"
			.'"Project-Id-Version: PACKAGE VERSION\n"'."\n"
			.'"Report-Msgid-Bugs-To: http://fplanque.net/\n"'."\n"
			.'"POT-Creation-Date: 2004-04-26 03:00+0200\n"'."\n"
			.'"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"'."\n"
			.'"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"'."\n"
			.'"Language-Team: LANGUAGE <LL@li.org>\n"'."\n"
			.'"MIME-Version: 1.0\n"'."\n"
			.'"Content-Type: text/plain; charset=CHARSET\n"'."\n"
			.'"Content-Transfer-Encoding: 8bit\n"'."\n"
		);

		$count = 0;

		foreach( $this->msgids as $msgid => $arr )
		{
			if( isset($arr['source']) )
			{ // write sources of string
				foreach( $arr['source'] as $source )
				{
					fwrite( $fh, '#: ../../'.$source."\n" );
				}
			}
			fwrite( $fh, 'msgid "'.$msgid.'"'."\nmsgstr ".'""'."\n\n" );

			$count++;

		}

		fclose( $fh );

		log_($count.' msgids written.');
		return true;
	}

}

?>
