package OOXMLconvert;

import java.io.File;
import java.text.DecimalFormat;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

/**
 *
 * @author ferou
 */
public class OOXMLstyles {
	
	// pomocne premenne
	/** default veľkosť fontu */
	public int defFontSize = 0;
	/** default výška riadku */
	public double lineHeight = 1;
	/** default odsadenie pred odstavcom */
	public int spacingBefore = 0;
	/** default odsadenie za odstavcom */
	public int spacingAfter = 0;
	
	/** zoznam štýlov a pre každý z nich zoznam properties */
	private LinkedHashMap<String,LinkedHashMap<String,String>> stylesrPr = null;
	/** zoznam štýlov pre paragraph a pre každý z nich zoznam properties */
	private LinkedHashMap<String,LinkedHashMap<String,String>> stylespPr = null;
	
	/**
	 * Funkcia vráti CSS štýl zodpovedajúci borderu
	 * @param pBdrChild element, v ktorom je definovaný border
	 * @return String obsahujúci CSS štýl
	 */
	private String getBorderProperties(Element pBdrChild) {
		try {
			String retString = "";
			String color = pBdrChild.getAttributeValue("color", Global.wns);
			String type = pBdrChild.getAttributeValue("val", Global.wns);
			String sizeS = pBdrChild.getAttributeValue("sz", Global.wns);
			int sizeI = Functions.intValDef(sizeS, 0);
			// nacitaj defaulty
			
			// farba
			if (color == null) {
				color = "black";
			}
			else {
				if (color.equals("auto")) {
					color = "black";
				}
				else {
					color = "#" + color;
				}
			}
			
			// typ ciary (registruj iba dashed a ostatne je solid)
			if (type == null) {
				type = "solid";
			}
			else if (type.contains("dash")) {
				type = "dashed";
			}
			else {
				type = "solid";
			}
			
			// hrubka ciary
			// premen jednotky pouzivane vo Worde na hrubku borderu na pixely
			sizeI = sizeI / 3;
			if (sizeI <= 0) {
				sizeI = 1;
			}
			
			retString = sizeI + "px " + type + " " + color;
			return retString;
		}
		catch (Exception e) {
			System.err.println(this.getClass().getName() + " (getBorderProperties): " + e.toString());
			return "";
		}
	}
	
	/**
	 * Funkcia prečíta daný style element a zapíše obsah do stylesrPr.
	 * @param elStyle element so štýlom
	 */
	private void readStyle(Element elStyle) {
		try {
			LinkedHashMap<String,String> style = new LinkedHashMap<String,String>();
			String styleId = elStyle.getAttributeValue("styleId", Global.wns);
			
			Element rPrEl = elStyle.getChild("rPr", Global.wns);
			if (rPrEl != null) {
				// prejdi vsetkych potomkov (formatovacie elementy)
				List children = rPrEl.getChildren();
				Iterator iterator = children.iterator();
				while (iterator.hasNext()) {
					Element child = (Element) iterator.next();

					// strike
					if (child.getName().trim().equals("strike")) {
						style.put("strike", child.getAttributeValue("val", Global.wns, "on").equals("none")?"off":"on");
					}
					// sub & super
					if (child.getName().trim().equals("vertAlign")) {
						String val = child.getAttributeValue("val", Global.wns);
						if (val.trim().equals("subscript")) {
							style.put("sub", "on");
						}
						else if (val.trim().equals("superscript")) {
							style.put("super", "on");
						}
					}
					// underline
					if (child.getName().trim().equals("u")) {
						style.put("u", child.getAttributeValue("val", Global.wns, "on").equals("none")?"off":"on");
					}
					// italic
					else if (child.getName().trim().equals("i")) {
						style.put("i", child.getAttributeValue("val", Global.wns, "on"));
					}
					// bold
					else if (child.getName().trim().equals("b")) {
						style.put("b", child.getAttributeValue("val", Global.wns, "on"));
					}
					// velkost fontu
					else if (child.getName().trim().equals("sz")) {
						String fontSize = child.getAttributeValue("val", Global.wns, "0");
						style.put("fontSize", fontSize);
					}
					// nazov fontu
					else if (child.getName().trim().equals("rFonts")) {
						String fontName = child.getAttributeValue("ascii", Global.wns, "");
						style.put("fontName", fontName);
					}
					// farba pisma
					else if (child.getName().trim().equals("color")) {
						String color = child.getAttributeValue("val", Global.wns, "");
						style.put("color", color);
					}
					// farba pozadia (paragraph)
					else if (child.getName().trim().equals("shd")) {
						String bkgColor = child.getAttributeValue("fill", Global.wns, "");
						style.put("bkgColor", bkgColor);
					}
					// farba pozadia (run)
					else if (child.getName().trim().equals("highlight")) {
						String bkgColor2 = child.getAttributeValue("val", Global.wns, "");
						style.put("bkgColor2", bkgColor2);
					}

				}
				// do stylov prenes aj nazov stylu, pre neskorsie urcovanie nadpisov a podobne...
				style.put("styleId", styleId);
			}
			stylesrPr.put(styleId, style);
			
			// styly pre paragraph
			LinkedHashMap<String,String> styleP = new LinkedHashMap<String,String>();
			
			Element pPrEl = elStyle.getChild("pPr", Global.wns);
			if (pPrEl != null) {
				// prejdi vsetkych potomkov (formatovacie elementy)
				List children = pPrEl.getChildren();
				Iterator iterator = children.iterator();
				while (iterator.hasNext()) {
					Element child = (Element) iterator.next();
					// cislovanie
					if (child.getName().trim().equals("numPr")) {
						Element ilvlEl = child.getChild("ilvl", Global.wns);
						Element numIdEl = child.getChild("numId", Global.wns);
						int ilvl = 0;
						if (ilvlEl != null) {
							ilvl = Functions.intValDef(ilvlEl.getAttributeValue("val", Global.wns, ""), 0);
						}
						String numId = numIdEl.getAttributeValue("val", Global.wns);
						LinkedHashMap<String,String> numb = Global.ooxmlNumberings.getNumbering(numId, ilvl);
						if (numb != null) {
							String numType = numb.get("numFmt");
							String numText = numb.get("lvlText");
							String numPicId = numb.get("lvlPicBulletId");
							styleP.put("numLevel", ilvl+"");
							styleP.put("numType", numType);
							styleP.put("numText", numText);
							styleP.put("numPicId", numPicId);
						}
					}
					// pozadie
					else if (Global.ooxmlPreserve.background && child.getName().trim().equals("shd")) {
						String bkgColor = child.getAttributeValue("fill", Global.wns, "");
						styleP.put("bkgColor", bkgColor);
					}
					// zarovnanie textu
					else if (Global.ooxmlPreserve.alignment && child.getName().trim().equals("jc")) {
						String align = child.getAttributeValue("val", Global.wns, "left");
						if (align.equals("left")) {
							styleP.put("align", "left");
						}
						else if (align.equals("right")) {
							styleP.put("align", "right");
						}
						else if (align.equals("center")) {
							styleP.put("align", "center");
						}
						else if (align.equals("both")) {
							styleP.put("align", "justify");
						}
					}
					// border
					else if (Global.ooxmlPreserve.border && child.getName().trim().equals("pBdr")) {
						List pBdrChildren = child.getChildren();
						Iterator pBdrIterator = pBdrChildren.iterator();
						while (pBdrIterator.hasNext()) {
							Element pBdrChild = (Element) pBdrIterator.next();
							if (pBdrChild.getName().trim().equals("top")) {
								String props = getBorderProperties(pBdrChild);
								styleP.put("border-top", props);
							}
							if (pBdrChild.getName().trim().equals("left")) {
								String props = getBorderProperties(pBdrChild);
								styleP.put("border-left", props);
							}
							if (pBdrChild.getName().trim().equals("bottom")) {
								String props = getBorderProperties(pBdrChild);
								styleP.put("border-bottom", props);
							}
							if (pBdrChild.getName().trim().equals("right")) {
								String props = getBorderProperties(pBdrChild);
								styleP.put("border-right", props);
							}
						}
					}
					// odsadenie
					else if (Global.ooxmlPreserve.indentation && child.getName().trim().equals("ind")) {
						int leftIndent = Functions.intValDef(child.getAttributeValue("left", Global.wns, "0"),0) / 15;
						int rightIndent = Functions.intValDef(child.getAttributeValue("right", Global.wns, "0"),0) / 15;
						if (leftIndent > 0) {
							styleP.put("leftIndent", leftIndent + "");
						}
						if (rightIndent > 0) {
							styleP.put("rightIndent", rightIndent + "");
						}
					}
					// vyska riadku
					else if (Global.ooxmlPreserve.linespacing && child.getName().trim().equals("spacing")) {
						DecimalFormat df = new DecimalFormat("0.00"); 
						double line = 1.0 * Functions.intValDef(child.getAttributeValue("line", Global.wns, "0"),0) / 240; // 240tina riadku
						String lineRule = child.getAttributeValue("lineRule", Global.wns, "auto").trim();
						int before = Functions.intValDef(child.getAttributeValue("before", Global.wns, "-100"),-100) / 15;
						int after = Functions.intValDef(child.getAttributeValue("after", Global.wns, "-100"),-100) / 15;

						if (lineRule.equals("auto")) {
							if (line <= 0) {
								line = Global.ooxmlStyles.lineHeight;
							}
							styleP.put("lineHeight", df.format(line).replace(",", "."));
						}

						if (before < 0) {
							before = Global.ooxmlStyles.spacingBefore;
						}
						styleP.put("spacingBefore", before + "");

						if (after < 0) {
							after = Global.ooxmlStyles.spacingAfter;
						}
						styleP.put("spacingAfter", after + "");
					}
				}
				styleP.put("styleId", styleId);
			}
			stylespPr.put(styleId, styleP);
		}
		catch (Exception e) {
			System.err.println(this.getClass().getName() + " (readStyle): " + e.toString());
		}
	}
	
	/**
	 * Funkcia načíta default štýly (veľkosť fontu).
	 * @param elStyle element s default štýlom
	 */
	private void readStyleDefaults(Element elStyle) {
		try {
			Element rPrEl = null;
			try {
				rPrEl = elStyle.getChild("rPrDefault", Global.wns).getChild("rPr", Global.wns);
			}
			catch (NullPointerException npe) {
				rPrEl = null;
			}
			if (rPrEl != null) {
				List children = rPrEl.getChildren();
				Iterator iterator = children.iterator();
				while (iterator.hasNext()) {
					Element child = (Element) iterator.next();
					if (child.getName().trim().equals("sz")) {
						// velkost fontu
						String fontSize = child.getAttributeValue("val", Global.wns);
						if (fontSize == null) {
							fontSize = "0";
						}
						defFontSize = Functions.intValDef(fontSize, 0);
						defFontSize = defFontSize / 2;
						if (defFontSize <= 0) {
							defFontSize = Global.defFontSizeConst;
						}
					}
				}
			}
			Element pPrEl = null;
			try {
				pPrEl = elStyle.getChild("pPrDefault", Global.wns).getChild("pPr", Global.wns);
			}
			catch (NullPointerException npe) {
				pPrEl = null;
			}
			if (pPrEl != null) {
				List children = pPrEl.getChildren();
				Iterator iterator = children.iterator();
				while (iterator.hasNext()) {
					Element child = (Element) iterator.next();
					if (child.getName().trim().equals("spacing")) {
						// vyska riadku, medzera pred a za odstavcom
						lineHeight = 1.0 * Functions.intValDef(child.getAttributeValue("line", Global.wns,"240"),240) / 240;
						spacingBefore = Functions.intValDef(child.getAttributeValue("before", Global.wns,"0"),0) / 15;
						spacingAfter = Functions.intValDef(child.getAttributeValue("after", Global.wns,"0"),0) / 15;
					}
				}
			}
		}
		catch (Exception e) {
			System.err.println(this.getClass().getName() + " (readStyleDefaults): " + e.toString());
		}
	}
	
	/**
	 * Funkcia prečíta štýly a zapíše ich do stylesrPr.
	 * @return <i>true</i> ak nenastala chyba, <i>false</i> inak
	 */
	public boolean readStyles() {
		try {
			File stylesFile = Global.ooxmlRels.stylesFile;
			if ((stylesFile != null) && (stylesFile.exists())) {
				stylesrPr = new LinkedHashMap<String, LinkedHashMap<String, String>>();
				stylespPr = new LinkedHashMap<String, LinkedHashMap<String, String>>();
				SAXBuilder builder = new SAXBuilder();
				Document doc = builder.build(stylesFile);
				Element root = doc.getRootElement();
				// najprv precitaj defaulty
				try {
					Element defaults = root.getChild("docDefaults", Global.wns);
					readStyleDefaults(defaults);
				}
				catch (NullPointerException e) {
					//System.out.println("Upozornenie: Default štýl nebol nájdený!");
					defFontSize = Global.defFontSizeConst;
				}
				// precitaj vsetky style elementy
				List children = root.getChildren("style",Global.wns);
				Iterator iterator = children.iterator();
				while (iterator.hasNext()) {
					Element child = (Element) iterator.next();
					readStyle(child);
				}
			}
			return true;
		}
		catch (Exception e) {
			System.err.println(this.getClass().getName() + " (readStyles): " + e.toString());
			return false;
		}
	}
	
	/**
	 * Funkcia vráti daný štýl.
	 * @param styleId názov štýlu
	 * @return mapu všetkých atribútov daného štýlu
	 */
	public LinkedHashMap<String,String> getStyle(String styleId) {
		try {
			if (this.stylesrPr.containsKey(styleId)) {
				return this.stylesrPr.get(styleId);
			}
			else {
				//System.out.println("Upozornenie: " + styleId + " štýl nebol nájdený!");
				return null;
			}
		}
		catch (Exception e) {
			System.err.println(this.getClass().getName() + " (getStyle): " + e.toString());
			return null;
		}
	}

	/**
	 * Funkcia vráti daný štýl.
	 * @param styleId názov štýlu
	 * @return mapu všetkých atribútov daného štýlu
	 */
	public LinkedHashMap<String,String> getPStyle(String styleId) {
		try {
			if (this.stylespPr.containsKey(styleId)) {
				return this.stylespPr.get(styleId);
			}
			else {
				//System.out.println("Upozornenie: " + styleId + " štýl nebol nájdený!");
				return null;
			}
		}
		catch (Exception e) {
			System.err.println(this.getClass().getName() + " (getPStyle): " + e.toString());
			return null;
		}
	}

}
