////////////////////////////////////////////////////////////////////////////////
//
// ADOBE SYSTEMS INCORPORATED
// Copyright 2007-2010 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE:  Adobe permits you to use, modify, and distribute this file 
// in accordance with the terms of the license agreement accompanying it.
//
////////////////////////////////////////////////////////////////////////////////
package flashx.textLayout.conversion
{
	import flash.utils.Dictionary;
	
	import flashx.textLayout.elements.IConfiguration;
	import flashx.textLayout.elements.TextFlow;
	import flashx.textLayout.elements.TextRange;
	import flashx.textLayout.tlf_internal;
	
	use namespace tlf_internal;
	
	/** 
	 * This is the gateway class for handling import and export. It serves as a unified access point to the 
	 * conversion functionality in the Text Layout Framework. It contains a registry for predefined as well
	 * as user defined input and/or output converters, plus a set of conversion methods.
	 * <p>
	 * The format of the converted data is not predefined; user written converters are free to accept and return
	 * any format of their choice. Common formats are strings, XML, and ByteArray instances. Converter authors 
	 * should document which formats are supported.
	 * </p>
	 * @includeExample examples\TextConverter_example.as -noswf
	 * @playerversion Flash 10
	 * @playerversion AIR 1.5
	 * @langversion 3.0
	 */
	public class TextConverter
	{
		/** 
		 * HTML format.
		 * Use this for importing from, or exporting to, a TextFlow using the HTML fomat.
		 * The Text Layout Framework HTML supports a subset of the tags and attributes supported by
		 * the TextField class in the <code>flash.text</code> package.
		 * <p>The following table lists the HTML tags and attributes supported for the import
		 * and export process (tags and attributes supported by TextField, but not supported by 
		 * the Text Layout Framework are specifically described as not supported):</p>
		 * 
		 * 
		 * <table class="innertable" width="640">
		 * 
		 * <tr>
		 * 
		 * <th>
		 * Tag
		 * </th>
		 * 
		 * <th>
		 * Description
		 * </th>
		 * 
		 * </tr>
		 * 
		 * <tr>
		 * 
		 * <td>
		 * Anchor tag
		 * </td>
		 * 
		 * <td>
		 * The <code>&lt;a&gt;</code> tag creates a hypertext link and supports the following attributes:
		 * <ul>
		 * 
		 * <li>
		 * <code>target</code>: Specifies the name of the target window where you load the page. 
		 * Options include <code>_self</code>, <code>_blank</code>, <code>_parent</code>, and 
		 * <code>_top</code>. The <code>_self</code> option specifies the current frame in the current window, 
		 * <code>_blank</code> specifies a new window, <code>_parent</code> specifies the parent of the 
		 * current frame, and <code>_top</code> specifies the top-level frame in the current window. 
		 * </li>
		 *
		 * <li>
		 * <code>href</code>: Specifies a URL. The URL can 
		 * be either absolute or relative to the location of the SWF file that 
		 * is loading the page. An example of an absolute reference to a URL is 
		 * <code>http://www.adobe.com</code>; an example of a relative reference is 
		 * <code>/index.html</code>. Absolute URLs must be prefixed with 
		 * http://; otherwise, Flash treats them as relative URLs. 
		 * <strong>Note: Unlike the TextField class, </strong>ActionScript <code>link</code> events 
		 * are not supported. Neither are
		 * <code>a:link</code>, <code>a:hover</code>, and <code>a:active</code> styles.
		 * </li>
		 * 
		 * </ul>
		 * 
		 * </td>
		 * </tr>
		 * 
		 * <tr>
		 * 
		 * <td>
		 * Bold tag
		 * </td>
		 * 
		 * <td>
		 * The <code>&lt;b&gt;</code> tag renders text as bold. A bold typeface must be available for the font used.
		 * </td>
		 * </tr>
		 * 
		 * <tr>
		 * 
		 * <td>
		 * Break tag
		 * </td>
		 * <td>
		 * The <code>&lt;br&gt;</code> tag creates a line break in the text.
		 * </td>
		 * </tr>
		 * 
		 * <tr>
		 * 
		 * <td>
		 * Font tag
		 * </td>
		 * 
		 * <td>
		 * The <code>&lt;font&gt;</code> tag specifies a font or list of fonts to display the text.The font tag 
		 * supports the following attributes:
		 * <ul>
		 * 
		 * <li>
		 * <code>color</code>: Only hexadecimal color (<code>#FFFFFF</code>) values are supported. 
		 * </li>
		 * 
		 * <li>
		 * <code>face</code>: Specifies the name of the font to use. As shown in the following example, 
		 * you can specify a list of comma-delimited font names, in which case Flash Player selects the first available 
		 * font. If the specified font is not installed on the local computer system or isn't embedded in the SWF file, 
		 * Flash Player selects a substitute font. 
		 * </li>
		 * 
		 * <li>
		 * <code>size</code>: Specifies the size of the font. You can use absolute pixel sizes, such as 16 or 18 
		 * or relative point sizes, such as +2 or -4. 
		 * </li>
		 * 
		 * <li>
		 * <code>letterspacing</code>: Specifies the tracking (manual kerning) in pixels to be applied to the right of each character. 
		 * </li>
		 * 
		 * <li>
		 * <code>kerning</code>: Specifies whether kerning is enabled or disabled. A non-zero value enables kerning, while zero disables it.  
		 * </li>
		 * 
		 * </ul>
		 * 
		 * </td>
		 * </tr>
		 * 
		 * <tr>
		 * 
		 * <td>
		 * Image tag
		 * </td>
		 * 
		 * <td>
		 * The <code>&lt;img&gt;</code> tag lets you embed external image files (JPEG, GIF, PNG), SWF files, and 
		 * movie clips inside text.  
		 * 
		 *  <p>The <code>&lt;img&gt;</code> tag supports the following attributes: </p>
		 * 
		 * <ul >
		 * 
		 * <li>
		 * <code>src</code>: Specifies the URL to an image or SWF file, or the linkage identifier for a movie clip 
		 * symbol in the library. This attribute is required; all other attributes are optional. External files (JPEG, GIF, PNG, 
		 * and SWF files) do not show until they are downloaded completely. 
		 * </li>
		 * 
		 * <li>
		 * <code>width</code>: The width of the image, SWF file, or movie clip being inserted, in pixels. 
		 * </li>
		 * 
		 * <li>
		 * <code>height</code>: The height of the image, SWF file, or movie clip being inserted, in pixels. 
		 * </li>
		 * </ul>
		 * <p><strong>Note: </strong> Unlike the TextField class, the following attributes are not supported:
		 * <code>align</code>, <code>hspace</code>, <code>vspace</code>,  <code>id</code>, and <code>checkPolicyFile</code>.</p>
		 *
		 * </td>
		 * </tr>
		 * 
		 * <tr>
		 * 
		 * <td>
		 * Italic tag
		 * </td>
		 * 
		 * <td>
		 * The <code>&lt;i&gt;</code> tag displays the tagged text in italics. An italic typeface must be available 
		 * for the font used.
		 * </td>
		 * </tr>
		 * 
		 * <tr>
		 * 
		 * <td>
		 * <em>List item tag</em>
		 * </td>
		 * 
		 * <td>
		 * <strong>Note: </strong> Unlike the TextField class, the List item tag is not supported.
		 * </td>
		 * </tr>
		 * 
		 * <tr>
		 * 
		 * <td>
		 * Paragraph tag
		 * </td>
		 * 
		 * <td>
		 * The <code>&lt;p&gt;</code> tag creates a new paragraph. 
		 * 
		 * The <code>&lt;p&gt;</code> tag supports the following attributes:
		 * <ul >
		 * 
		 * <li>
		 * align: Specifies alignment of text within the paragraph; valid values are <code>left</code>, <code>right</code>, <code>justify</code>, and <code>center</code>. 
		 * </li>
		 * 
		 * <li>
		 * class: Specifies a class name that can be used for styling 
		 * </li>
		 * 
		 * </ul>
		 * 
		 * </td>
		 * </tr>
		 * 
		 * <tr>
		 * 
		 * <td>
		 * Span tag
		 * </td>
		 * 
		 * <td>
		 * 
		 * The <code>&lt;span&gt;</code> tag supports the following attributes:
		 * 
		 * <ul>
		 * 
		 * <li>
		 * class: Specifies a class name that can be used for styling. While span tags are often used to set a style defined in a style sheet,
		 * TLFTextField instances do not support style sheets. The span tag is available for TLFTextField instances to refer to a class with 
		 * style properties.</li>
		 * <li> You can also put properties directly in the span tag: 
		 * <code>&lt;span fontFamily="Arial"&gt;Hi there&lt;/span&gt;</code>. However, nested span tags are not supported.
		 * </li>
		 * 
		 * </ul>
		 * 
		 * </td>
		 * </tr>
		 * 
		 * <tr>
		 * 
		 * <td>
		 * Text format tag
		 * </td>
		 * 
		 * <td>
		 *  <p>The <code>&lt;textformat&gt;</code> tag lets you use a subset of paragraph formatting 
		 * properties of the TextFormat class within text fields, including line leading, indentation, 
		 * margins, and tab stops. You can combine <code>&lt;textformat&gt;</code> tags with the 
		 * built-in HTML tags. </p>
		 * 
		 *  <p>The <code>&lt;textformat&gt;</code> tag has the following attributes: </p>
		 * <ul >
		 * 
		 * 
		 * <li>
		 * <code>indent</code>: Specifies the indentation from the left margin to the first character 
		 * in the paragraph; corresponds to <code>TextFormat.indent</code>. Both positive and negative 
		 * numbers are acceptable. 
		 * </li>
		 * 
		 * <li>
		 * <code>blockindent</code>: Specifies the indentation applied to all lines of the paragraph.
		 * </li>
		 * 
		 * <li>
		 * <code>leftmargin</code>: Specifies the left margin of the paragraph, in points; corresponds 
		 * to <code>TextFormat.leftMargin</code>. 
		 * </li>
		 * 
		 * <li>
		 * <code>rightmargin</code>: Specifies the right margin of the paragraph, in points; corresponds 
		 * to <code>TextFormat.rightMargin</code>. 
		 * </li>
		 * 
		 * 	<li>
		 * <code>leading</code>: Specifies the leading (line height) measured in pixels between a line's ascent and the previous line's descent
		 * </li>
		 * 
		 * 	<li>
		 * <code>tabstops</code>: Specifies a comma-separated list of tab stop positions for the paragraph. 
		 * </li>
		 * </ul>
		 * 
		 * </td>
		 * </tr>
		 * 
		 * <tr>
		 * 
		 * <td>
		 * Underline tag
		 * </td>
		 * 
		 * <td>
		 * The <code>&lt;u&gt;</code> tag underlines the tagged text.
		 * </td>
		 * </tr>
		 * 
		 * </table>
		 * 
		 * <p>When an unknown tag is imported the <code>textFieldHTMLFormat</code> importer will either set a single FlowElement's typeName property to that tag name
		 * or create a DivElement or a SubParagraphGroupElement with its typeName property set to the tag name.</p>
		 * <p>The <code>textFieldHTMLFormat</code> exporter will export <code>typeName</code> as the XML tag when it is different from the default.</p>
		 * 
		 * @see flashx.textLayout.elements.FlowElement#typeName
		 *
		 * @playerversion Flash 10
		 * @playerversion AIR 1.5
	 	 * @langversion 3.0 
		 */
		public static const TEXT_FIELD_HTML_FORMAT:String = "textFieldHTMLFormat";

		/** 
		 * Plain text format.
		 * Use this for creating a TextFlow from a simple, unformatted String, 
		 * or for creating a simple, unformatted String from a TextFlow.
		 * @playerversion Flash 10
		 * @playerversion AIR 1.5
	 	 * @langversion 3.0 
		 */
		public static const PLAIN_TEXT_FORMAT:String = "plainTextFormat";

		/** 
		 * TextLayout Format.
		 * Use this for importing from, or exporting to, a TextFlow using the TextLayout markup format.
		 * Text Layout format will detect the following errors:
		 * <ul>
		 * <li>Unexpected namespace</li>
		 * <li>Unknown element</li>
		 * <li>Unknown attribute</li>
		 * </ul>
		 * @playerversion Flash 10
		 * @playerversion AIR 1.5
	 	 * @langversion 3.0 
		 */
		public static const TEXT_LAYOUT_FORMAT:String = "textLayoutFormat";
		
		// Descriptors - ordered list of all FormatDescriptors
		/** @private */
		static tlf_internal var _descriptors:Array = [];

		// register standard importers and exporters
		setFormatsToDefault();
		
		/** @private */
		static tlf_internal function setFormatsToDefault():void	// No PMD
		{
			_descriptors = [];
			addFormat(TEXT_LAYOUT_FORMAT, TextLayoutImporter, TextLayoutExporter, TEXT_LAYOUT_FORMAT);
			addFormat(TEXT_FIELD_HTML_FORMAT, TextFieldHtmlImporter,  TextFieldHtmlExporter, null);
			addFormat(PLAIN_TEXT_FORMAT, PlainTextImporter, PlainTextExporter, "air:text");
		}
		
		/** 
		 * Creates a TextFlow from source content in a specified format.
		 * <p>Use one of the static constants supplied with this class, a MIME type,
		 * to specify the <code>format</code> parameter, or use a user defined
		 * value for user-registered importers:
		 * <ul>
		 * <li>TextConverter.TEXT_FIELD_HTML_FORMAT</li>
		 * <li>TextConverter.PLAIN_TEXT_FORMAT</li>
		 * <li>TextConverter.TEXT_LAYOUT_FORMAT</li>
		 * </ul>
		 * </p>
		 * @param source	Source content
		 * @param format	Format of source content
		 * @param config    IConfiguration to use when creating new TextFlows
		 * @return TextFlow that was created from the source, or null on errors.
		 * @playerversion Flash 10
		 * @playerversion AIR 1.5
		 * @langversion 3.0 
		 * @see #TEXT_FIELD_HTML_FORMAT
		 * @see #PLAIN_TEXT_FORMAT
		 * @see #TEXT_LAYOUT_FORMAT
		 */
		public static function importToFlow(source:Object, format:String, config:IConfiguration = null) : TextFlow
		{
			var parser:ITextImporter = getImporter(format, config);
			if (!parser)
				return null;
			parser.throwOnError = false;
			return parser.importToFlow(source);
		}
		
		/** 
		 * Exports a TextFlow to a specified format. 
		 * <p>Use one of the static constants supplied with this class, a MIME type,
		 * or a user defined format for user defined exporters to specify 
		 * the <code>format</code> parameter:
		 * <ul>
		 * <li>TextConverter.TEXT_FIELD_HTML_FORMAT</li>
		 * <li>TextConverter.PLAIN_TEXT_FORMAT</li>
		 * <li>TextConverter.TEXT_LAYOUT_FORMAT</li>
		 * </ul>
		 * </p>
		 * <p>Specify the type of the exported data in the <code>conversionType</code> parameter 
		 * with one of the static constants supplied by the ConversionType class, or a user defined
		 * data type for user defined exporters:
		 * <ul>
		 * <li>ConversionType.STRING_TYPE</li>
		 * <li>ConversionType.XML_TYPE</li>
		 * </ul>
		 * </p>
		 * 
		 * Returns a representation of the TextFlow in the specified format, or null on errors.
		 * @playerversion Flash 10
		 * @playerversion AIR 1.5
	 	 * @langversion 3.0 
		 * @param source	Source content
		 * @param format	Output format
		 * @param conversionType	Type of exported data
		 * @return Object	Exported form of the TextFlow, or null on errors
		 * @see #TEXT_FIELD_HTML_FORMAT
		 * @see #PLAIN_TEXT_FORMAT
		 * @see #TEXT_LAYOUT_FORMAT
		 * @see flashx.textLayout.conversion.ConversionType
		 */
		public static function export(source:TextFlow, format:String, conversionType:String) : Object
		{
			var exporter:ITextExporter = getExporter(format);
			if (!exporter)
				return null;
			exporter.throwOnError = false;
			return exporter.export(source, conversionType);
		}
		
		/** 
		 * Creates and returns an import converter, which you can then use to import from a 
		 * source string, an XML object, or any user defined data formats to a TextFlow. 
		 * Use this method if you have many separate imports to perform, or if you want to 
		 * handle errors during import. It is equivalent to calling 
		 * <code>flashx.textLayout.conversion.TextConverter.importToFlow()</code>.
		 * <p>Use one of the static constants supplied with this class
		 * to specify the <code>format</code> parameter, a MIME type, or a user defined
		 * data format.
		 * <ul>
		 * <li>TextConverter.TEXT_FIELD_HTML_FORMAT</li>
		 * <li>TextConverter.PLAIN_TEXT_FORMAT</li>
		 * <li>TextConverter.TEXT_LAYOUT_FORMAT</li>
		 * </ul>
		 * </p>
		 * <p>If the format has been added multiple times, the first one found will be used.</p>
		 * @includeExample examples\getImporter_example.as -noswf
		 * @playerversion Flash 10
		 * @playerversion AIR 1.5
	 	 * @langversion 3.0 
		 * @param format	Format of source content. Use constants from 
		 * 					flashx.textLayout.conversion.TextConverter.TEXT_LAYOUT_FORMAT, PLAIN_TEXT_FORMAT, TEXT_FIELD_HTML_FORMAT etc,
		 * 					a MIME type, or a user defined format.
		 * @param config    configuration to use during this import. null means take the current default.
		 * 					You can also set the configuration via the <code>ITextImporter.configuration</code>
		 * 					property.
		 * @return ITextImporter	Text importer that can import the source data
		 * @see #TEXT_FIELD_HTML_FORMAT
		 * @see #PLAIN_TEXT_FORMAT
		 * @see #TEXT_LAYOUT_FORMAT
		 */
		public static function getImporter(format:String,config:IConfiguration =  null): ITextImporter
		{
			var importer:ITextImporter = null;
			var i:int = findFormatIndex(format);
			if (i >= 0)
			{
				var descriptor:FormatDescriptor = _descriptors[i];
				if (descriptor && descriptor.importerClass)
				{
					importer = new descriptor.importerClass();
					importer.configuration = config;
				}
			}
			return importer;
		}

		/** 
		 * Creates and returns an export converter, which you can then use to export from 
		 * a TextFlow to a source string or XML object. Use this function if 
		 * you have many separate exports to perform. It is equivalent to calling 
		 * <code>flashx.textLayout.conversion.TextConverter.export()</code>.
		 * <p>Use one of the static constants supplied with this class
		 * to specify the <code>format</code> parameter:
		 * <ul>
		 * <li>TextConverter.TEXT_FIELD_HTML_FORMAT</li>
		 * <li>TextConverter.PLAIN_TEXT_FORMAT</li>
		 * <li>TextConverter.TEXT_LAYOUT_FORMAT</li>
		 * </ul>
		 * </p>
		 * <p>If the format has been added multiple times, the first one found will be used.</p>
		 * @includeExample examples\getExporter_example.as -noswf
		 * @playerversion Flash 10
		 * @playerversion AIR 1.5
	 	 * @langversion 3.0 
		 * @param format	Target format for exported data
		 * @return ITextExporter	Text exporter that can export in the specified format
		 * @see #TEXT_FIELD_HTML_FORMAT
		 * @see #PLAIN_TEXT_FORMAT
		 * @see #TEXT_LAYOUT_FORMAT
		 */
		public static function getExporter(format:String) : ITextExporter
		{
			var exporter:ITextExporter = null;
			var i:int = findFormatIndex(format);
			if (i >= 0)
			{
				var descriptor:FormatDescriptor = _descriptors[i];
				if (descriptor && descriptor.exporterClass)
					exporter = new descriptor.exporterClass();
			}
			return exporter;
		}

		/**
		 * Register a new format for import/export, at the specified location.
		 * Location can be significant for clients that have multiple 
		 * choices for which format to use, such as when importing from the external clipboard. 
		 * Lower numbers indicate higher priority; these converters will be tried first.
		 * The new format may support importing and/or exporting.
		 * If the format has already been added, then it will be present in multiple locations. The 
		 * first one found will be used.
		 * 
		 * @playerversion Flash 10
		 * @playerversion AIR 1.5
		 * @langversion 3.0 
		 * @param importClass    The import converter class to register or null
		 * @param exportClass    The export converter class to register or null
		 * @param format         The format string tagging the converter classes
		 * @param clipboardFormat	The string used as the clipboard format when converting to/from the clipboard. Make this null if the format doesn't support clipboard access.
		 */
		public static function addFormatAt(index:int, format:String, importerClass:Class, exporterClass:Class = null, clipboardFormat:String = null):void
		{
			var descriptor:FormatDescriptor = new FormatDescriptor(format, importerClass, exporterClass, clipboardFormat);
			_descriptors.splice(index, 0, descriptor);
		}
		
		/**
		 * Register a new format for import/export. The new format will be added at the end,
		 * as the lowest priority. Location can be significant for clients that have multiple 
		 * choices for which format to use, such as when importing from the external clipboard. 
		 * The new format may support importing and/or exporting.
		 * If the format has already been added, then it will be present in multiple locations. The 
		 * first one found will be used.
		 * @playerversion Flash 10
		 * @playerversion AIR 1.5
		 * @langversion 3.0 
		 * @param importClass    The import converter class to register or null
		 * @param exportClass    The export converter class to register or null
		 * @param format         The format string tagging the converter classes. Formats can be any name, but must be unique. 
		 * @param clipboardFormat	The string used as the clipboard format when converting to/from the clipboard. Make this null if the format doesn't support clipboard access.
		 */
		public static function addFormat(format:String, importerClass:Class, exporterClass:Class, clipboardFormat:String):void
		{
			addFormatAt(_descriptors.length, format, importerClass, exporterClass, clipboardFormat);
		}
		
		/**
		 * Remove the format at the index location. 
		 *
		 * @playerversion Flash 10
		 * @playerversion AIR 1.5
		 * @langversion 3.0 
		 * @param index     The format to remove
		 */
		public static function removeFormatAt(index:int):void
		{
			if (index >= 0 && index < _descriptors.length)
				_descriptors.splice(index, 1);
		}

		private static function findFormatIndex(format:String):int
		{
			for (var i:int = 0; i < numFormats; i++)
			{
				if (_descriptors[i].format == format)
					return i;
			}
			return -1;
		}
		/**
		 * Remove the format. 
		 * If a format was added multiple times, only the first one found is removed.
		 * 
		 * @playerversion Flash 10
		 * @playerversion AIR 1.5
		 * @langversion 3.0 
		 * @param format     The converter format string to remove
		 */
		public static function removeFormat(format:String):void
		{
			removeFormatAt(findFormatIndex(format));
		}
		
		/** Returns the format name for the index'th format.
		 * @playerversion Flash 10
		 * @playerversion AIR 1.5
		 * @langversion 3.0 
	     */
		public static function getFormatAt(index:int):String
		{
			return _descriptors[index].format;
		}

		/** Returns the FormatDescriptor for the index'th format. 
		* @playerversion Flash 10
		* @playerversion AIR 1.5
		* @langversion 3.0 
		*/
		public static function getFormatDescriptorAt(index:int):FormatDescriptor
		{
			return _descriptors[index];
		}
	
		/** Number of formats.
		* @playerversion Flash 10
		* @playerversion AIR 1.5
		* @langversion 3.0 
		*/
		public static function get numFormats():int
		{
			return _descriptors.length;
		}
	}
}
