/*
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * "The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations under
 * the License.
 *
 * The Original Code is ICEpdf 3.0 open source software code, released
 * May 1st, 2009. The Initial Developer of the Original Code is ICEsoft
 * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
 * 2004-2009 ICEsoft Technologies Canada, Corp. All Rights Reserved.
 *
 * Contributor(s): _____________________.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
 * License), in which case the provisions of the LGPL License are
 * applicable instead of those above. If you wish to allow use of your
 * version of this file only under the terms of the LGPL License and not to
 * allow others to use your version of this file under the MPL, indicate
 * your decision by deleting the provisions above and replace them with
 * the notice and other provisions required by the LGPL License. If you do
 * not delete the provisions above, a recipient may use your version of
 * this file under either the MPL or the LGPL License."
 *
 */
package com.softwareimaging.jpdf.core.pobjects.fonts;

import com.softwareimaging.data.ILogicalStreamReader;
import com.softwareimaging.data.SeekOrigin;
import com.softwareimaging.exceptions.FileHandlerNotInitializedException;
import com.softwareimaging.jpdf.core.pobjects.*;
import com.softwareimaging.jpdf.core.util.Library;
import com.softwareimaging.jpdf.util.HashMap;
import com.softwareimaging.jpdf.util.Hashtable;

import java.util.Vector;

/**
 * This class represents a PDF <code>FontDescriptor</code>. A FontDescriptor
 * object holds extra information about a particular parent Font object. In
 * particular information on font widths, flags, to unicode and embedded font
 * program streams.
 * 
 * @see com.softwareimaging.jpdf.core.pobjects.fonts.Font
 */
public class FontDescriptor extends Dictionary {

	public static final String FONT_NAME = "FontName";

	public static final String FONT_FAMILY = "FontFamily";

	public static final String MISSING_Stretch = "FontStretch";

	public static final String FONT_WEIGHT = "FontWeight";

	public static final String FLAGS = "Flags";

	public static final String FONT_BBOX = "FontBBox";

	public static final String ITALIC_ANGLE = "ItalicAngle";

	public static final String ASCENT = "Ascent";

	public static final String DESCENT = "Descent";

	public static final String LEADING = "Leading";

	public static final String CAP_HEIGHT = "CapHeight";

	public static final String X_HEIGHT = "XHeight";

	public static final String STEM_V = "StemV";

	public static final String STEM_H = "StemH";

	public static final String AVG_WIDTH = "AvgWidth";

	public static final String MAX_WIDTH = "MaxWidth";

	public static final String MISSING_WIDTH = "MissingWidth";

	public static final int FLAGS_FIXEDPITCH = (1 << (1 - 1));
	public static final int FLAGS_SERIF = (1 << (2 - 1));
	public static final int FLAGS_SYMBOLIC = (1 << (3 - 1));
	public static final int FLAGS_SCRIPT = (1 << (4 - 1));
	public static final int FLAGS_NONSYMBOLIC = (1 << (6 - 1));
	public static final int FLAGS_ITALIC = (1 << (7 - 1));
	public static final int FLAGS_ALLCAP = (1 << (17 - 1));
	public static final int FLAGS_SMALLCAP = (1 << (18 - 1));
	public static final int FLAGS_FORCEBOLD = (1 << (19 - 1));

	private static final String FONT_FILE = "FontFile";
	private static final String FONT_FILE_2 = "FontFile2";
	private static final String FONT_FILE_3 = "FontFile3";

	/**
	 * Creates a new instance of a FontDescriptor.
	 * 
	 * @param l
	 *            Libaray of all objects in PDF
	 * @param h
	 *            hash of parsed FontDescriptor attributes
	 */
	public FontDescriptor(Library l, Hashtable h) {
		super(l, h);
	}

	/**
	 * Returns the PostScript name of the font.
	 * 
	 * @return PostScript name of font.
	 */
	public String getFontName() {
		Object value = library.getObject(entries, FONT_NAME);
		if (value instanceof Name) {
			return ((Name) value).getName();
		}
		return null;
	}

	/**
	 * Gets a string specifying the preferred font family name. For example, the
	 * font "Time Bold Italic" would have a font family of Times.
	 * 
	 * @return preferred font family name.
	 */
	public String getFontFamily() {
		Object value = library.getObject(entries, FONT_FAMILY);
		if (value instanceof StringObject) {
			StringObject familyName = (StringObject) value;
			return familyName.getDecryptedLiteralString(library.getSecurityManager());
		}
		return null;
	}

	/**
	 * Gets the weight (thickness) component of the fully-qualified font name or
	 * font specifier. The default value is zero.
	 * 
	 * @return the weight of the font name.
	 */
	public float getFontWeight() {
		Object value = library.getObject(entries, FONT_WEIGHT);
		if (value instanceof Number) {
			return ((Number) value).floatValue();
		}
		return 0.0f;
	}

	/**
	 * Gets the width to use for character codes whose widths are not specifed
	 * in the font's dictionary. The default value is zero.
	 * 
	 * @return width of non-specified characters.
	 */
	public float getMissingWidth() {
		Object value = library.getObject(entries, MISSING_WIDTH);
		if (value instanceof Number) {
			return ((Number) value).floatValue();
		}
		return 0.0f;
	}

	/**
	 * Gets the average width of glyphs in the font. The default value is zero.
	 * 
	 * @return average width of glyphs.
	 */
	public float getAverageWidth() {
		Object value = library.getObject(entries, AVG_WIDTH);
		if (value instanceof Number) {
			return ((Number) value).floatValue();
		}
		return 0.0f;
	}

	/**
	 * Gets the maximum width of glyphs in the font. The default value is zero.
	 * 
	 * @return maximum width of glyphs.
	 */
	public float getMaxWidth() {
		Object value = library.getObject(entries, MAX_WIDTH);
		if (value instanceof Number) {
			return ((Number) value).floatValue();
		}
		return 0.0f;
	}

	/**
	 * Gets the ascent of glyphs in the font. The default value is zero.
	 * 
	 * @return ascent of glyphs.
	 */
	public float getAscent() {
		Object value = library.getObject(entries, ASCENT);
		if (value instanceof Number) {
			return ((Number) value).floatValue();
		}
		return 0.0f;
	}

	/**
	 * Gets the descent of glyphs in the font. The default value is zero.
	 * 
	 * @return descent of glyphs.
	 */
	public float getDescent() {
		Object value = library.getObject(entries, DESCENT);
		if (value instanceof Number) {
			return ((Number) value).floatValue();
		}
		return 0.0f;
	}

	/**
	 * Gets the fonts bounding box.
	 * 
	 * @return bounding box in PDF coordinate space.
	 */
	public PRectangle getFontBBox() {
		Object value = library.getObject(entries, FONT_BBOX);
		if (value instanceof Vector) {
			Vector rectangle = (Vector) value;
			return new PRectangle(rectangle);
		}
		return null;
	}

	/**
	 * Gets the font flag value, which is a collection of various
	 * characteristics that describe the font.
	 * 
	 * @return int value representing the flags; bits must be looked at to get
	 *         attribute values.
	 */
	public int getFlags() {
		Object value = library.getObject(entries, FLAGS);
		if (value instanceof Number) {
			return ((Number) value).intValue();
		}
		return 0;
	}

	/**
	 * Gets the embedded font stream specified by key
	 * 
	 * @param key
	 *            FONT_FILE, FONT_FILE2 or FONT_FILE3
	 * @return embedded font stream
	 */
	private ILogicalStreamReader getFontStream(String key) {
		ILogicalStreamReader data = null;
		if (entries.containsKey(key)) {
			Stream fontStream = (Stream) library.getObject(entries, key);
			if (fontStream != null) {
				data = fontStream.getFileStreamReader(true);
			}
		}
		return data;
	}

	/**
	 * Gets the FontFile stream
	 * 
	 * @return FontFile stream
	 */
	public ILogicalStreamReader getFontFile() {
		return getFontStream(FONT_FILE);
	}

	/**
	 * Gets the FontFile2 stream
	 * 
	 * @return FontFile2 stream
	 */
	public ILogicalStreamReader getFontFile2() {
		return getFontStream(FONT_FILE_2);
	}

	/**
	 * Gets the FontFile3 stream
	 * 
	 * @return FontFile3 stream
	 */
	public ILogicalStreamReader getFontFile3() {
		return getFontStream(FONT_FILE_3);
	}

	/**
	 * Get the lengths of the Type 1 font data. The first element is the length
	 * (Length1) in byte of the clear-text portion. The second element is the
	 * length (Length2) in byte of the encrypted portion. The third (last)
	 * element is the length (Length3) in byte of the fixed-content portion.
	 * 
	 * @return the lengths of the Type 1 font data
	 */
	public int[] getFontLengths() {
		int[] lengths = new int[] { -1, -1, -1 };
		if (entries.containsKey(FONT_FILE)) {
			Stream fontStream = (Stream) library.getObject(entries, FONT_FILE);
			Integer length1 = (Integer) fontStream.getEntries().get("Length1");
			if (length1 != null) {
				lengths[0] = length1.intValue();
			}
			Integer length2 = (Integer) fontStream.getEntries().get("Length2");
			if (length2 != null) {
				lengths[1] = length2.intValue();
			}
			Integer length3 = (Integer) fontStream.getEntries().get("Length3");
			if (length3 != null) {
				lengths[2] = length3.intValue();
			}
		}
		return lengths;
	}

	/**
	 * Initiate the Font Descriptor object. Reads embedded font programs or CMap
	 * streams.
	 */
	public void init() {

	}
}
