package com.adobe.epubcheck.cli;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URL;

import org.junit.Test;

import com.adobe.epubcheck.tool.Checker;

public class CLITest {
	private static String epubPath = "/30/epub/";
	private static String expPath = "/30/expanded/";
	private static String singlePath = "/30/single/";
	
	@Test
	public void testNPE() {		
		assertEquals(1, run(null));		
	}
	
	@Test
	public void testValidEPUB() {		
		assertEquals(0, run(new String[]{epubPath + "valid/lorem.epub"}));		
	}
	
	@Test
	public void testValidEPUBArchive() {		
		assertEquals(0, run(new String[]{expPath + "valid/lorem-basic-ncx/", "-mode", "exp", "-save"}));
		
		// since issue #255 we need the absolute path to check the saved outfile
		File baseDirParent = new File(getAbsoluteBasedir(expPath + "valid/lorem-basic-ncx/")).getParentFile();
		File out = new File(baseDirParent + File.separator + "lorem-basic-ncx.epub");
		
		assertTrue(out.exists());
		if(out.exists()) out.delete();
	}
	
	@Test
	public void testInvalidEPUB() {		
		assertEquals(1, run(new String[]{epubPath + "invalid/lorem-xht-sch-1.epub"}));		
	}
	
	@Test
	public void testValidExp() {		
		assertEquals(0, run(new String[]{expPath + "valid/lorem-basic/", "-mode", "exp"}));		
	}
	
	@Test
	public void testInvalidExp() {		
		assertEquals(1, run(new String[]{expPath + "invalid/lorem-xhtml-rng-1/", "-mode", "exp"}));		
	}
	
	@Test
	public void testValidSingle() {		
		assertEquals(0, run(new String[]{singlePath + "nav/valid/nav001.xhtml", "-mode", "nav"}));		
	}
	
	@Test
	public void testInvalidSingle() {		
		assertEquals(1, run(new String[]{singlePath + "nav/invalid/noTocNav.xhtml", "-mode", "nav"}));		
	}
	
	@Test
	public void testValidExtension1() { 
		assertEquals(1, run(new String[]{epubPath + "valid/extension-1.ePub"}));
	}
	
	@Test
	public void testOutputXMLCreation() {
		File xmlOut1 = new File("outfile.xml");
		if(xmlOut1.exists()) xmlOut1.delete();
		
		assertEquals(0, run(new String[]{epubPath + "valid/lorem.epub", "-out", "outfile.xml"}));	
		
		assertTrue(xmlOut1.exists());
		if(xmlOut1.exists()) xmlOut1.delete();
	}
	
	@Test
	public void testOutputXMLCreation_ModeExpanded() {
		File xmlOut2 = new File("outfile2.xml");
		if(xmlOut2.exists()) xmlOut2.delete();
		
		assertEquals(1, run(new String[]{expPath + "invalid/lorem-xhtml-rng-1/", "-mode", "exp", "-out", "outfile2.xml"}));	
		
		assertTrue(xmlOut2.exists());
		if(xmlOut2.exists()) xmlOut2.delete();
	}
	
	@Test
	public void testQuietRun() {
		PrintStream outOrig = System.out;
		CountingOutStream outCount = new CountingOutStream();
		System.setOut(new PrintStream(outCount));
		String epubFilePath = getAbsoluteBasedir(epubPath + "valid/lorem.epub");
		int result = Checker.run(new String[]{ epubFilePath, "-quiet" });
		System.setOut(outOrig);
		assertEquals(0, result);
		// System.err.println("Output [" + outCount.getValue() + "]");
		assertEquals("Output [" + outCount.getValue() + "]", 0, outCount.getCounts());
	}

	@Test
	public void testQuietRunWithOutput() {
		final String xmlOutFileName = "outfile4.xml";
		final File xmlOut = new File(xmlOutFileName);
		if(xmlOut.exists()) xmlOut.delete();

		PrintStream outOrig = System.out;
		CountingOutStream outCount = new CountingOutStream();
		System.setOut(new PrintStream(outCount));
		String epubFilePath = getAbsoluteBasedir(epubPath + "valid/lorem.epub");
		int result = Checker.run(new String[]{ epubFilePath, "-quiet", "-out", xmlOutFileName});
		System.setOut(outOrig);
		assertEquals(0, result);
		// System.err.println("Output [" + outCount.getValue() + "]");
		assertEquals("Output [" + outCount.getValue() + "]", 0, outCount.getCounts());

		assertTrue(xmlOut.exists());
		if(xmlOut.exists()) xmlOut.delete();
	}
		
	private int run(String[] args, boolean verbose) {
		PrintStream outOrig = System.out;
		PrintStream errOrig = System.err;
		if (!verbose) {			
			System.setOut(new NullPrintStream());
			System.setErr(new NullPrintStream());
		}
		if (args != null) {
			args[0] = getAbsoluteBasedir(args[0]);
		}
		int result = Checker.run(args);		
		System.setOut(outOrig);
		System.setErr(errOrig);		
		return result;
	}
	
	private int run(String[] args) {
		return run(args, false);
	}
	
	private String getAbsoluteBasedir(String base) {
		URL fileURL = this.getClass().getResource(base);
		return fileURL!=null?fileURL.getPath():base;
	}

	class CountingOutStream extends OutputStream {
		int counts;
		StringBuilder sb = new StringBuilder();
		
		public int getCounts() { return counts; }
		
		public String getValue() { return sb.toString(); }
		
        @Override
        public void write(int b) {
        	sb.append((char)b);
            counts++;
        }

    }
	
	class NullPrintStream extends PrintStream {
		public NullPrintStream() {
			super(new OutputStream() {				
				@Override
				public void write(int b) throws IOException {
					
				}
			});
		}		
	}
}	
	
