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

import java.io.*;
import java.net.URLEncoder;
import java.util.*;

public class Base extends BPPCompiledScript
{
	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 GeneralUtils.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 GeneralUtils.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 GeneralUtils.isEmptyString(obj);
	}

	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 boolean isMovieFile(File file)
	{
		return isFileFromTypes( file, MediaUtils.getSupportedVideoTypes() );
	}

	public boolean isAudioFile(File file)
	{
		return isFileFromTypes( file, MediaUtils.getSupportedAudioTypes() );
	}

	private boolean isFileFromTypes(File file, String[] types)
	{
		String myFileName = getFileName(file);

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

			for( int i=0; i<types.length; i++ )
			{
				if( fileExtension.equalsIgnoreCase("." + types[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 String encodeUrlIfNecessary(String url)
	{
		if( !engine.isUrlEncode() || isEmptyString(url) )
			return url;

		String result = URLEncoder.encode( url );

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

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

	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];
		}
	}
}
