import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.StringTokenizer;

import org.zefer.pd4ml.PD4Constants;
import org.zefer.pd4ml.PD4ML;
import org.zefer.pd4ml.PD4PageMark;

public class Pd4Cmd {

	private static String in;
	private static int width = -1;
	private static String format = "A4";
	private static int permissions = -1;
	private static String bookmarks;
	private static String orientation;
	private static String insets;
	private static String ttf;
	private static String out;
	private static boolean smart;

	private static boolean forms;
	private static boolean physUnits;
	private static boolean adjustWidth;
	private static boolean fitPage;
	private static boolean hyperlinks = true;
	private static boolean imgSplit = true;
	private static boolean pdfa;
	private static boolean debug;
	
	private static String author;
	private static String title;
	private static String range;
	private static String password;

	private static String bgcolor;
	private static String bgimage;

	private static ArrayList styles;
	
	private static HashMap cookies;
	private static HashMap dynParams;
	
	private static String header;
	private static String footer;
	
	private void generatePDF() throws Exception {

		PD4ML pd4ml = new PD4ML();

		if (insets != null) {
			StringTokenizer st = new StringTokenizer(insets, ",");
			try {
				int top = Integer.parseInt(st.nextToken());
				int left = Integer.parseInt(st.nextToken());
				int bottom = Integer.parseInt(st.nextToken());
				int right = Integer.parseInt(st.nextToken());
				String units = st.nextToken();
				Insets ins = new Insets(top, left, bottom, right);
				if ("mm".equalsIgnoreCase(units)) {
					pd4ml.setPageInsetsMM(ins);
				} else {
					pd4ml.setPageInsets(ins);
				}
			} catch (Exception e) {
				throw new Exception(
						"Invalid page insets (top, left, bottom, right, units): "
								+ insets);
			}
		}

		pd4ml.setHtmlWidth(width);

		try {
			Class c = PD4Constants.class;
			Field f = c.getField( format );
			Dimension d = (Dimension) f.get(pd4ml);

			if (orientation != null && "LANDSCAPE".equalsIgnoreCase(orientation)) {
				d = pd4ml.changePageOrientation(d);
			}

			pd4ml.setPageSize(d);
		} catch (Exception e) {
			StringTokenizer st = new StringTokenizer( format, "x");
			try {
				int width = Integer.parseInt(st.nextToken());
				int height = Integer.parseInt(st.nextToken());
				if ( height < 1 || width < 1 ) {
					throw new Exception("nop");
				}
				
				Dimension d = new Dimension(width,height);
				if (orientation != null && "LANDSCAPE".equalsIgnoreCase(orientation)) {
					d = pd4ml.changePageOrientation(d);
				}

				pd4ml.setPageSize(d);
			} catch (Exception ex) {
				throw new Exception( "Invalid page format: " + format );
			}
		}

		pd4ml.enableTableBreaks(smart);

		if (permissions != -1) {
			if ( password != null ) {
				pd4ml.setPermissions(password, permissions, true);
			} else {
				pd4ml.setPermissions("empty", permissions, true);
			}
		} else {
			if ( password != null ) {
				pd4ml.setPermissions(password, 0xfffffffc, true);
			}
		}

		if (bookmarks != null) {
			if ("ANCHORS".equalsIgnoreCase(bookmarks)) {
				pd4ml.generateOutlines(false);
			} else if ("HEADINGS".equalsIgnoreCase(bookmarks)) {
				pd4ml.generateOutlines(true);
			}
		}

		if (ttf != null && ttf.length() > 0) {
			pd4ml.useTTF(ttf, true);
		}

		if (forms) {
			pd4ml.generatePdfForms(true, "Arial");
		}

		if (physUnits) {
			pd4ml.protectPhysicalUnitDimensions();
		}

		if (adjustWidth) {
			pd4ml.adjustHtmlWidth();
		}

		if (fitPage) {
			pd4ml.fitPageVertically();
		}

		if (!hyperlinks) {
			pd4ml.disableHyperlinks();
		}

		if (!imgSplit) {
			pd4ml.enableImgSplit(false);
		}

		if (author != null ) {
			pd4ml.setAuthorName(author);
		}

		if (title != null ) {
			pd4ml.setDocumentTitle(title);
		}

		if (range != null ) {
			pd4ml.outputRange(range);
		}

		if (dynParams != null ) {
			pd4ml.setDynamicParams(dynParams);
		}

		if (styles != null ) {
			Iterator ii = styles.iterator();
			while (ii.hasNext()) {
				String style = (String)ii.next();
				pd4ml.addStyle(style, true);
			}
		}

		if (cookies != null ) {
			Iterator ii = cookies.keySet().iterator();
			while (ii.hasNext()) {
				String key = (String)ii.next();
				String value = (String)cookies.get(key);
				pd4ml.setCookie(key, value);
			}
		}

		if (pdfa) {
			pd4ml.generatePdfa(true);
		}

		if ( footer != null && footer.trim().length() > 0 || 
				bgimage != null && bgimage.trim().length() > 0 || 
				bgcolor != null && bgcolor.trim().length() > 0  ) {
			
			PD4PageMark footerObj = new PD4PageMark();
			footerObj.setAreaHeight(-1); // autocompute
			try {
				if ( footer != null && footer.trim().length() > 0 ) {
					footerObj.setHtmlTemplate(footer);
				}
				
				if ( bgimage != null && bgimage.trim().length() > 0 ) {
					footerObj.setPageBackgroundImageUrl(bgimage);
				}
				
				if ( bgcolor != null && bgcolor.trim().length() > 0 ) {
					Color c = Color.decode(bgcolor);
					footerObj.setPageBackgroundColor(c);
				}
				
				pd4ml.setPageFooter(footerObj);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		if ( header != null && header.trim().length() > 0 ) {
			PD4PageMark headerObj = new PD4PageMark();
			headerObj.setAreaHeight(-1); // autocompute
			headerObj.setHtmlTemplate(header);
			pd4ml.setPageHeader(headerObj);
		}

		if (debug) {
			pd4ml.enableDebugInfo();
		}

		if (out != null) {
			FileOutputStream fos = new FileOutputStream(out);
			pd4ml.render(new URL(in), fos);
			fos.close();
		} else {
			pd4ml.render(new URL(in), System.out);
		}
	}
	
	public static void main(String[] args) throws Exception {
		
		boolean formatSet = false;
		
		char quote = File.pathSeparatorChar == '\\' ? '\"' : '\'';
		String USAGE = "Usage: java -Xmx512m [-Djava.awt.headless=true] Pd4Cmd "+quote+"<url>"+quote+" <htmlWidth> [pageFormatName|WxH] " +
		"[-pdfa] [-smarttablesplit] [-permissions <NUMBER>] [-bookmarks <HEADINGS|ANCHORS>] " +
		"[-orientation <PORTRAIT|LANDSCAPE>] [-insets <T,L,B,R,><mm|pt>] [-bgcolor <#RGB>] [-bgimage "+quote+"<url>"+quote+"] [-ttf <ttf_fonts_dir>]" + 
		"[-addstyle <CSS code>] [-pdfforms] [-protectpud] [-adjustwidth] [-fitapage] [-nohyperlinks] [-noimagesplit] " +
		"[-author <author name>] [-title <title override>] [-cookie <name> <value>] [-param <name> <value>] [-header "+quote+"<header HTML code>"+quote+"] " +
		"[-footer "+quote+"<footer HTML code>"+quote+"] [-pagerange <page>] [-out <output_file_path>] [-password <password>] [-debug]";

		
		for( int i = 0; i < args.length; i++ ) {

			if ( "-pdfforms".equalsIgnoreCase( args[i] ) ) {
				forms = true;
				continue;
			}

			if ( "-protectpud".equalsIgnoreCase( args[i] ) ) {
				physUnits = true;
				continue;
			}

			if ( "-adjustwidth".equalsIgnoreCase( args[i] ) ) {
				adjustWidth = true;
				continue;
			}

			if ( "-fitapage".equalsIgnoreCase( args[i] ) ) {
				fitPage = true;
				continue;
			}

			if ( "-nohyperlinks".equalsIgnoreCase( args[i] ) ) {
				hyperlinks = false;
				continue;
			}

			if ( "-pdfa".equalsIgnoreCase( args[i] ) ) {
				pdfa = true;
				continue;
			}

			if ( "-noimagesplit".equalsIgnoreCase( args[i] ) ) {
				imgSplit = false;
				continue;
			}

			if ( "-debug".equalsIgnoreCase( args[i] ) ) {
				debug = true;
				continue;
			}

			if ( "-smarttablesplit".equalsIgnoreCase( args[i] ) ) {
				smart = true;
				continue;
			}

			if ( "-bgcolor".equals( args[i] ) ) {
				++i;
				if ( i == args.length ) {
					System.out.println("invalid parameter: color is missing (Example: -bgcolor "+quote+"#ffffcc"+quote+" or  -bgcolor 0xffffcc)");
					System.out.println( USAGE );
					return; 
				}
				bgcolor = args[i];
				continue;
			}
			
			if ( "-bgimage".equals( args[i] ) ) {
				++i;
				if ( i == args.length ) {
					System.out.println("invalid parameter: author name is missing (Example: -bgimage "+quote+"http://pd4ml.com/i/blank.jpg"+quote+" or -bgimage "+quote+"file:/resources/images/blank.jpg"+quote+")");
					System.out.println( USAGE );
					return; 
				}
				bgimage = args[i];
				continue;
			}
			
			if ( "-author".equals( args[i] ) ) {
				++i;
				if ( i == args.length ) {
					System.out.println("invalid parameter: author name is missing");
					System.out.println( USAGE );
					return; 
				}
				author = args[i];
				continue;
			}

			if ( "-title".equals( args[i] ) ) {
				++i;
				if ( i == args.length ) {
					System.out.println("invalid parameter: title override string is missing");
					System.out.println( USAGE );
					return; 
				}
				title = args[i];
				continue;
			}

			if ( "-password".equals( args[i] ) ) {
				++i;
				if ( i == args.length ) {
					System.out.println("invalid parameter: password string is missing");
					System.out.println( USAGE );
					return; 
				}
				password = args[i];
				continue;
			}

			if ( "-pagerange".equals( args[i] ) ) {
				++i;
				if ( i == args.length ) {
					System.out.println("invalid parameter: no output page range definition string (Example: -pagerange "+quote+"2-3,7+"+quote+")");
					System.out.println( USAGE );
					return; 
				}
				range = args[i];
				continue;
			}

			if ( "-header".equals( args[i] ) ) {
				++i;
				if ( i == args.length ) {
					System.out.println("invalid parameter: PDF header definition HTML code is missing (Example: -header "+quote+"<div width=100% align=right>$[page] of $[total]</div>"+quote+")");
					System.out.println( USAGE );
					return; 
				}
				header = args[i];
				continue;
			}

			if ( "-footer".equals( args[i] ) ) {
				++i;
				if ( i == args.length ) {
					System.out.println("invalid parameter: PDF footer definition HTML code is missing (Example: -footer "+quote+"<div width=100% align=right>$[page] of $[total]</div>"+quote+")");
					System.out.println( USAGE );
					return; 
				}
				footer = args[i];
				continue;
			}

			if ( "-addstyle".equals( args[i] ) ) {
				++i;
				if ( i == args.length ) {
					System.out.println("invalid parameter: style definition is missing  (Example: -addstyle "+quote+"IMG, TR {page-break-inside: avoid}"+quote+")");
					System.out.println( USAGE );
					return; 
				}
				
				if ( styles == null ) {
					styles = new ArrayList();
				}
				
				String style = args[i];
				styles.add(style);
				continue;
			}

			if ( "-cookie".equals( args[i] ) ) {
				++i;
				if ( i+1 == args.length ) {
					System.out.println("invalid parameter: incomplete cookie data  (Example: -cookie JSESSIONID "+quote+"9034657927465;path=/"+quote+")");
					System.out.println( USAGE );
					return; 
				}
				
				if ( cookies == null ) {
					cookies = new HashMap();
				}
				
				String key = args[i];
				String value = args[++i];
				
				cookies.put(key, value);
				continue;
			}

			if ( "-param".equals( args[i] ) ) {
				++i;
				if ( i+1 == args.length ) {
					System.out.println("invalid parameter: incomplete cookie data  (Example: -param pd4ml.basic.authentication "+quote+"user:password"+quote+")");
					System.out.println( USAGE );
					return; 
				}
				
				if ( dynParams == null ) {
					dynParams = new HashMap();
				}
				
				String key = args[i];
				String value = args[++i];
				
				dynParams.put(key, value);
				continue;
			}

			if ( "-permissions".equals( args[i] ) ) {
				++i;
				if ( i == args.length ) {
					System.out.println("invalid parameter: missing permissions number (a sum of single permission codes)");
					System.out.println( USAGE );
					return; 
				}
				permissions = Integer.parseInt(args[i]);
				continue;
			}

			if ( "-bookmarks".equals( args[i] ) ) {
				++i;
				if ( i == args.length ) {
					System.out.println("invalid parameter: missing bookmark type (HEADINGS or ANCHORS)");
					System.out.println( USAGE );
					return; 
				}
				bookmarks = args[i];
				continue;
			}

			if ( "-orientation".equals( args[i] ) ) {
				++i;
				if ( i == args.length ) {
					System.out.println("invalid parameter: missing orientation type (PORTRAIT or LANDSCAPE)");
					System.out.println( USAGE );
					return; 
				}
				orientation = args[i];
				continue;
			}

			if ( "-insets".equals( args[i] ) ) {
				++i;
				if ( i == args.length ) {
					System.out.println("invalid parameter: missing insets (for exampe: -insets 5,10,5,5mm)");
					System.out.println( USAGE );
					return; 
				}
				insets = args[i];
				continue;
			}

			if ( "-ttf".equals( args[i] ) ) {
				++i;
				if ( i == args.length ) {
					System.out.println("invalid parameter: missing TTF fonts directory");
					System.out.println( USAGE );
					return; 
				}
				ttf = args[i];
				continue;
			}

			if ( "-out".equals( args[i] ) ) {
				++i;
				if ( i == args.length ) {
					System.out.println("invalid parameter: missing output file name");
					System.out.println( USAGE );
					return; 
				}
				out = args[i];
				continue;
			}

			if ( args[i].startsWith("-")  ) {
				System.out.println("unknown parameter: " + args[i] );
				System.out.println( USAGE );
				return; 
			}

			if ( in == null ) {
				in = args[i];
				continue;
			}

			if ( width == -1 ) {
				width = Integer.parseInt(args[i]);
				continue;
			}

			if ( !formatSet ) {
				formatSet = true;
				format = args[i];
				continue;
			}

			System.out.println("unexpected parameter: " + args[i]);
			System.out.println( USAGE );
			return; 
		}
		
		if ( in == null ) {
			System.out.println("source URL is missing");
			System.out.println( USAGE );
			return;
		}

		if ( width == -1 ) {
			System.out.println("HTML width parameter is missing");
			System.out.println( USAGE );
			return;
		}
		
		if ( out == null ) {
			debug = false;
		}
		
		Pd4Cmd converter = new Pd4Cmd();
		converter.generatePDF(); 
	}
}

