import se.datadosen.jalbum.AlbumBean;
import se.datadosen.util.SmartResourceBundle;

import java.awt.*;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URLEncoder;
import java.util.*;
import javax.swing.*;

public class Base extends BPPCompiledScript
{
	private String[] supportedMovieTypes = {".AVI", ".MOV", ".MPG", ".MPEG", ".WMV", ".MP4", ".DIVX", ".XVID", ".3GP"};

	public Base(AlbumBean engine)
	{
		super(engine);
	}

	public Properties getFolderConfig(File dir, String file_name)
	{
		Map vars = getVariableContainer(dir);

		if( vars!=null )
		{
			String cache_key = Constants.CACHE_KEY_PREFIX + file_name;

			if( !vars.containsKey(cache_key) )
			{
				try
				{
					vars.put(cache_key, getFolderConfigImpl(dir, file_name));
				}
				catch( IOException e )
				{
					log("Error reading properties file", e);
					vars.put(cache_key, new Properties());
				}
			}

			return (Properties)vars.get(cache_key);
		}
		else
		{
			try
			{
				return getFolderConfigImpl(dir, file_name);
			}
			catch( IOException e )
			{
				log("Error reading properties file", e);
				return new Properties();
			}
		}
	}

	private Properties getFolderConfigImpl(File dir, String file_name) throws IOException
	{
		//File propsFile = new File((dir!=null) ? dir : imageDirectory, file_name);
		File propsFile = new File(resolveRealFile(dir), file_name);
		Properties props = null;

		// Seems that the IO.readProperties() doesn't do the job well when the keys contain spaces!
		if( propsFile.exists() )
		{
			props = new Properties();

			BufferedReader reader = new BufferedReader( new FileReader(propsFile) );
			String line;

			while( (line=reader.readLine())!=null )
			{
				line = line.trim();

				if( !line.startsWith("#") )
				{
					int index = line.indexOf("=");

					if( index!=-1 && index>0 )
					{
						String value = "";

						if( index<line.length()-1 )
							value = line.substring( index+1 ).trim();
						props.put( line.substring(0, index).trim(), value );
					}
				}
			}
		}

		return props;
	}

	public boolean isVariableValueEqual(String var_name, File dir, boolean var_value)
	{
		Object value = readUserVariableAsObject(var_name, dir);

		if( value instanceof Boolean )
			return( ((Boolean)value).booleanValue()==var_value );

		if( !isEmptyString(value) )
		{
			String str_value = value.toString().trim();

			if( str_value.equalsIgnoreCase("true") || str_value.equalsIgnoreCase("yes") )
				return var_value==true;
			else if( str_value.equalsIgnoreCase("false") || str_value.equalsIgnoreCase("no") )
				return var_value==false;
		}

		// Empty value means "TRUE" as the default for variables with "Include" prefix (a quick hack)!
		if( (var_name.toLowerCase().startsWith("include") && !var_name.equalsIgnoreCase(Constants.USER_VAR_INCLUDE_SAVE_PROTECTION) && !var_name.equalsIgnoreCase(Constants.USER_VAR_INCLUDE_BLENDING_EFFECT_ON_INDEXES))
			|| var_name.equalsIgnoreCase(Constants.USER_VAR_CYCLIC_SLIDE_SHOW)|| var_name.equalsIgnoreCase(Constants.USER_VAR_ENABLE_DEDICATED_SLIDE_COMMENT_SECTION) )
			return var_value==true;
		else
			return var_value==false;
	}

	public int readUserVariableAsInteger(String var_name, File dir, int default_value)
	{
		Object value = readUserVariableAsObject(var_name, dir);

		if( value instanceof Integer )
			return ((Integer)value).intValue();

		if( isEmptyString(value) )
			return default_value;
		else
			return convertToInteger(value);
	}

	public double readUserVariableAsDouble(String var_name, File dir, double default_value)
	{
		Object value = readUserVariableAsObject(var_name, dir);

		if( value instanceof Double )
			return ((Double)value).doubleValue();

		if( isEmptyString(value) )
			return default_value;
		else
			return convertToDouble(value);
	}

	public String readUserVariableAsString(String var_name, File dir, String default_value)
	{
		Object value = readUserVariableAsObject(var_name, dir);

		if( isEmptyString(value) )
			return default_value;
		else
			return value.toString();
	}

	public Object readUserVariableAsObject(String var_name, File dir)
	{
		if( dir!=null && !dir.isDirectory() )
			dir = dir.getParentFile();

		Map vars = getVariableContainer(dir);

		if( vars!=null )
		{
			String cache_key = Constants.CACHE_KEY_FOLDER_USER_VARIABLE + var_name;

			if( !vars.containsKey(cache_key) )
				vars.put(cache_key, readUserVariableAsObjectImpl(var_name, dir));

			return vars.get(cache_key);
		}
		else
			return readUserVariableAsObjectImpl(var_name, dir);
	}

	private Object readUserVariableAsObjectImpl(String var_name, File dir)
	{
		Properties prop = getFolderConfig(dir, Constants.SKIN_FOLDER_LEVEL_VARIABLES);

		if( prop!=null && prop.containsKey(var_name) )
			return prop.get(var_name);

		while( !isTopLevelFolder(dir) )
		{
			dir = dir.getParentFile();
			prop = getFolderConfig(dir, Constants.SKIN_FOLDER_LEVEL_VARIABLES);
			if( prop!=null && prop.containsKey(var_name) )
				return prop.get(var_name);
		}

		if( engine.getSkinVariables().containsKey(var_name) )
			return engine.getSkinVariables().get(var_name);
		else
			return engine.getUserVariables().get(var_name);
	}

	public boolean isVariableDefined(String var_name, File dir)
	{
		Object value = readUserVariableAsObject(var_name, dir);

		return !isEmptyString(value);
	}

	public String readFromFolderMetadata(String var_name, File dir)
	{
		return readFromFolderMetadata(var_name, dir, false);
	}

	public String readFromFolderMetadata(String var_name, File dir, boolean check_parent)
	{
		return readFromFolderMetadataImpl(var_name, dir, check_parent, check_parent ? "../" : null);
	}

	private String readFromFolderMetadataImpl(String var_name, File dir, boolean check_parent, String parent_prefix)
	{
		if( dir!=null && !dir.isDirectory() )
			dir = dir.getParentFile();

		Properties prop = getFolderConfig(dir, Constants.SKIN_FOLDER_META_DATA);

		if( prop!=null && prop.containsKey(var_name) )
			return (String) prop.get(var_name);

		if( check_parent )
		{
			String my_prefix = "";

			while( !isTopLevelFolder(dir) )
			{
				dir = dir.getParentFile();
				if( !isEmptyString(parent_prefix) )
					my_prefix += parent_prefix;

				prop = getFolderConfig(dir, Constants.SKIN_FOLDER_META_DATA);
				if( prop!=null && prop.containsKey(var_name) )
				{
					if( !isEmptyString(parent_prefix) )
						return my_prefix + prop.get(var_name);
					else
						return (String) prop.get(var_name);
				}
			}
		}

		return null;
	}

	public boolean isTopLevelFolder(File dir)
	{
		return( dir==null || fileVariables.get(dir)==null );
	}

	public boolean isEmptyString(Object obj)
	{
		return( obj==null || obj.toString().trim().equals("") );
	}

	// Strip non-numeric ending on strings and convert result to double
	public double convertToDouble(Object obj)
	{
		if( isEmptyString(obj) )
			return 0;

		String str = obj.toString();
		int i;

		for (i=0; i<str.length(); i++)
		{
			char c = str.charAt(i);
			if (!Character.isDigit(c) && c!='.' && c!='+' && c!='-' )
				break;
		}
		if( i>0 )
			return Double.parseDouble(str.substring(0,i));
		else
			return 0;
	}

	// Strip non-numeric ending on strings and convert result to integer
	public int convertToInteger(Object obj)
	{
		if( isEmptyString(obj) )
			return 0;

		String str = obj.toString();
		int i;

		for (i=0; i<str.length(); i++)
		{
			char c = str.charAt(i);
			if (!Character.isDigit(c))
				break;
		}
		if( i>0 )
			return Integer.parseInt(str.substring(0,i));
		else
			return 0;
	}

	public String convertToString(Object obj)
	{
		if( obj==null )
			return null;
		return obj.toString();
	}

	public SmartResourceBundle getResourceBundle(String resourceBaseName, String cacheKey)
	{
		if( !album.containsKey(cacheKey) )
		{
			SmartResourceBundle texts;
			File baseResourceDir = new File(skinDirectory, "texts");
			String lang = language;

			if( lang!=null && !lang.trim().equals("") )
				texts = SmartResourceBundle.getBundle(baseResourceDir, resourceBaseName, new Locale(lang, ""));
			else
				texts = SmartResourceBundle.getBundle(baseResourceDir, resourceBaseName);
			album.put(cacheKey, texts);
		}

		return (SmartResourceBundle) album.get(cacheKey);
	}

	public String appendString(String main_str, String str_to_append, boolean tooltip)
	{
		String separator = tooltip ? " * " : " <br/>\n";

		return appendString(main_str, str_to_append, separator);
	}

	public String appendString(String main_str, String str_to_append, String separator)
	{
		if( isEmptyString(str_to_append) )
			return main_str;

		String result = main_str;

		if( result!=null && !result.trim().equals("") )
			result += separator;
		else
			result = "";

		return result + str_to_append;
	}

	public boolean isMovieFile(File file)
	{
		String myFileName = getFileName(file);

		if (myFileName.lastIndexOf(".")>0)
		{
			String fileType = myFileName.substring(myFileName.lastIndexOf(".")).trim();

			for( int i=0; i<supportedMovieTypes.length; i++ )
			{
				if( fileType.equalsIgnoreCase(supportedMovieTypes[i]) )
					return true;
			}
		}

		return false;
	}

	public String getFileName(File myfile)
	{
		myfile = resolveRealFile(myfile);

		Map vars = (Map)fileVariables.get(myfile);
		String result = null;

		if( vars!=null )
			result = (String) vars.get("fileName");

		if( isEmptyString(result) )
			result = myfile.getName();

		return result;
	}

	public String getLabel(File myfile)
	{
		myfile = resolveRealFile(myfile);

		Map vars = (Map)fileVariables.get(myfile);
		String result = null;

		if( vars!=null )
			result = (String) vars.get("label");

		if( isEmptyString(result) )
		{
			//int dot_index = myfile.getName().indexOf('.');
			int dot_index = myfile.getName().lastIndexOf('.');

			if( dot_index!=-1 )
				result = myfile.getName().substring(0, dot_index);
			else
				result = myfile.getName();
		}

		return result;
	}

	public Map getVariableContainer(File file)
	{
		file = resolveRealFile(file);

		if( fileVariables==null || file==null )
			return null;

		Map result = (Map)fileVariables.get(file);

		//The directory is top-most-level so doing a trick here and keep the top-most-level directory properties in 'album' object!
		if( file.isDirectory() && result==null )
			result = album;
		return result;
	}

	public Dimension getImageDimension(File image, int max_width, int max_height)
	{
		if( image==null || !image.exists() )
			return new Dimension(max_width, max_height);

		try
		{
			return getImageDimensionImpl(image, max_width, max_height);
		}
		catch( MalformedURLException e )
		{
			log("Error while calculating the dimension of the image!", e);
			return new Dimension(max_width, max_height);
		}
	}

	private Dimension getImageDimensionImpl(File image, int max_width, int max_height) throws MalformedURLException
	{
		ImageIcon imageIcon = new ImageIcon(image.toURL());
		Dimension size = new Dimension(imageIcon.getIconWidth(), imageIcon.getIconHeight());

		// By Igor Lubashev: A fix to OUT-OF-MEMORY problem! Seems the JVM does not free the memory used by this object.
		imageIcon.getImage().flush();

		// This shouldn't occur normally!
		if( size.width<=0 || size.height<=0 )
		{
			size.width = max_width;
			size.height = max_height;
		}

		/*if( size.width>max_width )
		{
			size.height = (size.height * max_width) / size.width;
			size.width = max_width;
		}

		if( size.height>max_height )
		{
			size.width = (size.width * max_height) / size.height;
			size.height = max_height;
		}*/

		return size;
	}

	public String clearHtmlCode(String str)
	{
		if( isEmptyString(str) || (str.indexOf("<")==-1 && str.indexOf("\"")==-1) )
			return str;

		StringBuffer buf = new StringBuffer();

		for( int i=0; i<str.length(); i++ )
		{
			char ch = str.charAt(i);

			if( ch=='<' )
			{
				i = str.indexOf(">", i);
				if( i==-1 )
					break;
			}
			else if( ch!='\"' )
				buf.append(ch);
		}

		return buf.toString();
	}

	public String encodeUrlIfNecessary(String url)
	{
		if( !engine.isUrlEncode() || isEmptyString(url) )
			return url;

		String result = URLEncoder.encode( url );

		//result = replaceAll(result, "\\x2B", "%20");
		result = replaceAll(result, "+", "%20");
		result = replaceAll(result, "%2F", "/");
		return result;
	}

	private String replaceAll(String str, String old, String replacement)
	{
		StringBuffer result = new StringBuffer(str);
		int index = 0;

		while( (index = result.toString().indexOf(old))!=-1 )
			result.replace(index, index+old.length(), replacement);
		return result.toString();
		//return str.replaceAll(old, replacement);
	}

	public String formatBigTemplate(String template, Object[] args)
	{
		StringBuffer result = new StringBuffer();

		for( int i=0; i<template.length(); i++ )
		{
			char ch = template.charAt(i);

			if( ch=='{' )
			{
				int index = template.indexOf("}", i);

				 if( index>i+1 )
				 {
					try
					{
						int arg_no = Integer.parseInt( template.substring(i+1, index) );
						Object arg = args[arg_no];

						result.append( (arg==null) ? arg : arg.toString() );
						i = index;
						continue;
					}
					catch( Exception e )
					{
					}
				 }
			}

			result.append(ch);
		}
		return result.toString();
	}

	protected File resolveRealFile(File file)
	{
		if( file==null ) //The current file/folder!
		{
			file = currentFile; // File
			if( file==null ) // Folder
				file = imageDirectory;
		}
		return file;
	}

	public String readTextFile(File file)
	{
		if( file!=null && file.exists() && file.length()>0 )
		{
			try
			{
				return se.datadosen.util.IO.readTextFile(file);
			}
			catch( IOException e )
			{
				log("Error reading text file!", e);
				return "";
			}
		}
		else
			return "";
	}

	protected void copyFile(File src, File dest)
	{
		try
		{
			se.datadosen.util.IO.copyFile(src, dest, true);
		}
		catch( IOException e )
		{
			log("Error copying file!", e);
		}
	}

	public File[] listFiles(File dir, boolean includeDirs, File outputDir)
	{
		try
		{
			return engine.listFiles(dir, includeDirs, outputDir);
		}
		catch( IOException e )
		{
			log("Error while listing files!", e);
			return new File[0];
		}
	}

	/*String htmlEncode(String s)
	{
		if( s==null || s.trim().equals("") )
			return s;

		StringBuffer str = new StringBuffer();

		for (int j = 0; j < s.length(); j++)
		{
			char c = s.charAt(j);

			// encode standard ASCII characters into HTML entities where needed
			if (c < '\200')
			{
				switch (c)
				{
					case '"':
						str.append("&quot;");
						break;

					case '&':
						str.append("&amp;");
						break;

					case '<':
						str.append("&lt;");
						break;

					case '>':
						str.append("&gt;");
						break;

					default:
						str.append(c);
				}
			}
			// encode 'ugly' characters (ie Word "curvy" quotes etc)
			else if (c < '\377')
			{
				String hexChars = "0123456789ABCDEF";
				int a = c % 16;
				int b = (c - a) / 16;
				String hex = "" + hexChars.charAt(b) + hexChars.charAt(a);

				str.append("&#x" + hex + ";");
			}
			//add other characters back in - to handle charactersets other than ascii
			else
			{
				str.append(c);
			}
		}

		return str.toString();
	}*/
}
