import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;




//import org.apache.commons.collections.map.HashedMap;
//import org.bouncycastle.jcajce.provider.digest.GOST3411.HashMac;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.almworks.sqlite4java.SQLiteConnection;
import com.almworks.sqlite4java.SQLiteStatement;


/**
 * Simple app-data info class, holds info on a folder's app with info to submit.
 * @author Luke Bryan
 *
 */
public class AppData implements DirData {
	
	private File _dir;
	private String _appTitle;
	private String _id;
	private int _numId;
	private String _iosversion;
	private File _apkFile;
	private File _whatsNewFile;
	private File _whatsNewiOS;
	private boolean _binaryOnly;

	/**
	 * Given directory of NUMBER/, gets important app-info.
	 * @param dir
	 * @throws Exception
	 */
	public AppData(File dir) throws Exception
	{
		this._binaryOnly = false;
		
		if( dir.isDirectory() )
		{
			DirectoryStream<Path> directory = Files.newDirectoryStream( dir.toPath() );
			this._numId = Integer.valueOf( dir.toPath().getFileName().toString() );
			for( Path entry : directory )
			{
				if( entry.getFileName().toString().length() == 12 )
				{
					_dir = entry.toFile();
				}
				else if( entry.getFileName().toString().equals( "app-release.apk" ) )
				{
					this._apkFile = entry.toFile();
				}
				else if( entry.getFileName().toString().equals( "whats_new_android.txt" ) )
				{
					this._whatsNewFile = entry.toFile();
				}
				else if( entry.getFileName().toString().equals( "whats_new.txt" ) )
				{
					this._whatsNewiOS = entry.toFile();
				}
				else if( entry.getFileName().toString().equals( "BINARYONLY" ) )
				{
					//Disabling this for now since ALL will need the new screenshot uploads.
					//this._binaryOnly = true;
				}
			}
			
			directory = Files.newDirectoryStream( _dir.toPath() );
			for( Path entry : directory ) 
			{
				if( entry.getFileName().toString().equals( "title_and_id.txt" ) )
				{
					BufferedReader br = new BufferedReader( new FileReader( entry.toFile() ) );
					_appTitle = br.readLine();
					_id = br.readLine().trim();
					br.close();
				}
				else if (entry.getFileName().toString().equals("data"))
				{
					File dbFile = new File(entry.toFile(), "com.sharefaith.churchapp.prebaked.sqlite");
					if( dbFile.exists())
					{
						SQLiteConnection conn = new SQLiteConnection( dbFile );
						conn.open(true);
						SQLiteStatement st = conn.prepare("SELECT count(*) FROM section_content");
						st.step();
						long count = st.columnLong(0);
						st.dispose();
						conn.dispose();
						/*if (count < 1)
						{
							throw new Exception ("Invalid sqlite?");
						}*/
					} else {
						throw new Exception ("Expected a sqlite file!");
					}
				}
			}
			
			if( !_id.startsWith( "com.sharefaith.churchapp" ) )
			{
				throw new Exception("Weird id " + _id);
			}
			
			
			InfoGetter infos = new InfoGetter( new File( dir, "/Sharefaith ChurchApp/ios/Sharefaith ChurchApp/Sharefaith ChurchApp-Info.plist" ) );
			_iosversion = infos.getInfo("CFBundleShortVersionString");
			if ( !infos.hasSermons )
			{
				SendMailTLS.mail( "Warning - no-sermons app", "This app will not include sermons:\n" + this.toString() );
			}
		}
		else
		{
			throw new Exception("not dir?");
		}
	}
	
	/**
	 * Get the data-dir (12-hex folder with data)
	 * @return
	 */
	public File getDataDir()
	{
		return _dir;
	}
	
	public int getNumericId()
	{
		return _numId;
	}
	
	/**
	 * Get the APK file
	 * @return
	 */
	public File getApkFile()
	{
		return _apkFile;
	}
	
	public File getWhatsNewFile()
	{
		return _whatsNewFile;
	}
	
	public File getWhatsNewiOS()
	{
		return _whatsNewiOS;
	}
	
	public String getId() {
		return _id;
	}
	
	public String getAndroID() {
		return  _id.replace("com.sharefaith.churchapp.", "com.sharefaith.sfchurchapp_");
	}
	
	public String getTitle() {
		return _appTitle;
	}
	
	public String getShortVersion() {
		return _iosversion;
	}
	
	public boolean isBinaryOnly()
	{
		return this._binaryOnly;
	}
	
	public String toString() {
		return "id=" + _id +
				"\ntitle=" + _appTitle +
				"\nversion=" + _iosversion;
	}

	//um why? duplicate
	public boolean isBinOnly() {
		return this._binaryOnly;
	}

	public void noBinOnly() {
		this._binaryOnly = false;
	}

}


/**
 * Simple plist-info-getter.
 * @author Luke Bryan
 */
class InfoGetter extends DefaultHandler
{
	
	public boolean hasSermons = false;
    String tmpValue;
    String lastKey = "";
    File myFile;
    HashMap<String, String> stringMap;
    
    public InfoGetter(File data) throws IOException
    {
    	myFile = data;
    	stringMap = new HashMap<String, String>();
    	parseDocument();
    }
    private void parseDocument() throws IOException
    {
        // parse
        SAXParserFactory factory = SAXParserFactory.newInstance();
        try {
            SAXParser parser = factory.newSAXParser();
            parser.parse(myFile, this);
        } catch (ParserConfigurationException e) {
            System.err.println("ParserConfig error");
        } catch (SAXException e) {
            System.err.println("SAXException : xml not well formed");
        }
    }
    
    public String getInfo(String key)
    {
    	return stringMap.get(key);
    }
    
    @Override
    public void startElement(String s, String s1, String elementName, Attributes attributes) throws SAXException
    {
    	tmpValue = "";
    }
    @Override
    public void endElement(String s, String s1, String element) throws SAXException
    {
        // if end of element add to list
        if (element.equals("key"))
        {
        	lastKey = tmpValue;
        }
        if (element.equals("string"))
        {
        	//This gets the LAST if array of <string> unfortunately
        	stringMap.put(lastKey, tmpValue);
        	
        	if (tmpValue.equals("audio") && lastKey.equals("UIBackgroundModes"))
        	{
        		this.hasSermons = true;
        	}
        }
    }
    @Override
    public void characters(char[] ac, int i, int j) throws SAXException {
        tmpValue = new String(ac, i, j);
    }
}