
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.*;
import java.util.List;

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

public class Common extends PhotographicMetaInformation
{
	private static final String MOVIE_BLOCK_TEMPLATE = "<embed align=\"center\" src=\"{0}\"" +
			" width=\"{1}\" height=\"{2}\" autoplay=\"true\" controller=\"true\" cache=\"true\"" +
			" pluginspage=\"http://www.apple.com/quicktime/download/\"></embed>\n";

	protected static final String VOICE_ANNOTATION_BLOCK_TEMPLATE = "<embed src=\"{0}\" width=\"{1}\" height=\"{2}\" controls=\"console\" autostart=\"true\"></embed>";
	protected static final String VOICE_ANNOTATION_HIDDEN_BLOCK_TEMPLATE = "<embed src=\"{0}\" hidden=\"true\" width=\"0\" height=\"0\" autostart=\"true\"></embed>";

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

	public String getIconSet(File dir)
	{
		String icon_set = readUserVariableAsString(Constants.USER_VAR_ICON_SET, dir, Constants.DEFAULT_ICON_SET);

		addToUsedObjects(icon_set, Constants.CACHE_KEY_USED_ICON_SETS);
		return icon_set;
	}

	public String getIconSetPath(File dir)
	{
		return resPath + Constants.SKIN_ACTION_RESOURCE_DIR + getIconSet(dir);
	}

	public String getStylePath(File dir)
	{
		String style = readUserVariableAsString(Constants.USER_VAR_STYLE, dir, this.style);
		String style_path = resPath + "/styles/" + style;
		int index = style.toLowerCase().indexOf(".css");

		addToUsedObjects(style, Constants.CACHE_KEY_USED_FULL_STYLES);
		if( index!=-1 )
			style = style.substring(0, index);
		addToUsedObjects(style, Constants.CACHE_KEY_USED_STYLES);
		return style_path;
	}

	private void addToUsedObjects(Object usedObj, Object key)
	{
		List usedObjects = (List) album.get(key);

		if( usedObjects==null )
		{
			usedObjects = new LinkedList();
			album.put(key, usedObjects);
		}

		if( !usedObjects.contains(usedObj) )
			usedObjects.add(usedObj);
	}

	public File getOriginalVoiceAnnotationFile(File file)
	{
		File baseDir = file.isDirectory() ? file : file.getParentFile();
		String voiceFileName;
		File sound;

		if( file.isDirectory() )
			voiceFileName = readFromFolderMetadata(Constants.META_FOLDER_VOICE, baseDir);
		else
			voiceFileName = readFromFolderMetadata(Constants.META_SLIDE_VOICE+getFileName(file), baseDir);

		if( !isEmptyString(voiceFileName) )
		{
			sound = new File(baseDir, voiceFileName);
			if( sound.exists() )
				return sound;
		}

		voiceFileName = getLabel(file);
		if( file.isDirectory() )
			voiceFileName = "_" + voiceFileName;

		return getExistentFile(baseDir, voiceFileName, new String[] {"wav", "mp3", "wma", "voc", "mid", "au", "rm"});
	}

	private File getExistentFile(File baseDir, String fileBaseName, String[] fileExtensions)
	{
		for( int i = 0; i<fileExtensions.length; i++ )
		{
			File file = new File(baseDir, fileBaseName + "." + fileExtensions[i]);

			if( file.exists() )
				return file;
		}
		return null;
	}

	public boolean isInsideAlbum(File file)
	{
		if( file==null )
			return false;
		else
		{
			try
			{
				return file.getCanonicalPath().startsWith(rootImageDirectory.getCanonicalPath());
			}
			catch( IOException e )
			{
				log(e);
				return false;
			}
		}
	}

	public File getBackgroundImageFile(String var_name, File dir)
	{
		String backgroundFileName = readFromFolderMetadata(var_name, dir, true);
		File background;

		if( !isEmptyString(backgroundFileName) )
		{
			background = new File(dir, backgroundFileName);
			if( background.exists() )
				return background;
			else
				displayMessage( "The specified background image '" + backgroundFileName + "' does not exist!" );
		}

		return null;
	}

	public String getSlideInternalComment(File myfile)
	{
		Map vars = getVariableContainer(myfile);

		if( !vars.containsKey(Constants.CACHE_KEY_SLIDE_INTERNAL_COMMENT) )
			vars.put(Constants.CACHE_KEY_SLIDE_INTERNAL_COMMENT, getSlideInternalCommentImpl(myfile));

		return (String)vars.get(Constants.CACHE_KEY_SLIDE_INTERNAL_COMMENT);
	}

	private String getSlideInternalCommentImpl(File myfile)
	{
		Map vars = (Map)fileVariables.get(resolveRealFile(myfile));
		String result = "";

		if( vars.get("comment")!=null )
			result = vars.get("comment").toString();
		return result;
	}

	public String getSlideExternalComment(File myfile, boolean tooltip)
	{
		Map vars = getVariableContainer(myfile);
		String key = Constants.CACHE_KEY_SLIDE_EXTERNAL_COMMENT + tooltip;

		if( !vars.containsKey(key) )
			vars.put(key, getSlideExternalCommentImpl(myfile, tooltip));

		return (String)vars.get(key);
	}

	private String getSlideExternalCommentImpl(File myfile, boolean tooltip)
	{
		File comment_file = new File(imageDirectory, getLabel(myfile)+".txt");
		String result = "";

		if( comment_file.exists() )
			result = readTextFile(comment_file);

		String desc = readFromFolderMetadata(Constants.META_SLIDE_DESCRIPTION + getFileName(myfile), imageDirectory);

		return appendString(result, desc, tooltip);
	}

	public String getThumbnailTooltip(File myfile)
	{
		Map vars = getVariableContainer(myfile);

		if( !vars.containsKey(Constants.CACHE_KEY_THUMBNAIL_TOOLTIP) )
			vars.put(Constants.CACHE_KEY_THUMBNAIL_TOOLTIP, getThumbnailInfoImpl(myfile, Constants.USER_VAR_THUMBNAIL_TOOLTIP_CONTENT, Constants.DEFAULT_THUMBNAIL_TOOLTIP_CONTENT, true));

		return (String)vars.get(Constants.CACHE_KEY_THUMBNAIL_TOOLTIP);
	}

	protected String getThumbnailInfoImpl(File myfile, String info_key, String default_value, boolean tooltip)
	{
		if( myfile==null )
			myfile = currentFile;

		Map meta = (Map)getVariableContainer(myfile).get("meta");
		String info_content = readUserVariableAsString(info_key, myfile, default_value);
		StringTokenizer st = new StringTokenizer(info_content, ",;|~");
		String result = "";

		while( st.hasMoreTokens() )
		{
			String token = st.nextToken().trim();

			if( token.equalsIgnoreCase("title") )
				result = appendString(result, getSlideTitle(myfile), tooltip);
			else if( token.equalsIgnoreCase("filename") )
				result = appendString(result, getFileName(myfile), tooltip);
			else if( token.equalsIgnoreCase("filetype") )
				result = appendString(result, "(" + FileFilters.getExtensionOf(myfile) + ")", tooltip);
			else if( token.equalsIgnoreCase("internalcomment") || token.equalsIgnoreCase("exifcomment") || token.equalsIgnoreCase("embeddedcomment") )
				result = appendString(result, getSlideInternalComment(myfile), tooltip);
			else if( token.equalsIgnoreCase("externalcomment") )
				result = appendString(result, getSlideExternalComment(myfile, tooltip), tooltip);
			else if( token.equalsIgnoreCase("dimension") )
				result = appendString(result, getFileDimension(myfile, true), tooltip);
			else if( token.equalsIgnoreCase("slidedimension") )
				result = appendString(result, getFileDimension(myfile, false), tooltip);
			else if( token.equalsIgnoreCase("filesize") )
				result = appendString(result, "(" + getFileSize(myfile) + ")", tooltip);
			else if( token.equalsIgnoreCase("date") )
				result = appendString(result, getSlideDate(myfile), tooltip);
			else if( meta!=null && meta.containsKey(token) )
				result = appendString(result, transformMetadataValue(token, meta.get(token)), " - ");
		}

		return( tooltip ? clearHtmlCode(result) : result );
	}

	public String getSlideDate(File myfile)
	{
		Map vars = (Map)fileVariables.get(resolveRealFile(myfile));
		Object myFileDate;

		if( vars.containsKey("originalDate") )
			myFileDate = vars.get("originalDate");
		else
			myFileDate = vars.get("fileDate");

		return myFileDate.toString();
	}

	public String getFileDimension(File myfile, boolean original)
	{
		Map vars = (Map)fileVariables.get(resolveRealFile(myfile));
		long myWidth;
		long myHeight;

		if( original )
		{
			myWidth = ((Integer)vars.get("originalWidth")).intValue();
			myHeight = ((Integer)vars.get("originalHeight")).intValue();
		}
		else
		{
			myWidth = ((Integer)vars.get("imageWidth")).intValue();
			myHeight = ((Integer)vars.get("imageHeight")).intValue();
		}

		return myWidth + " x " + myHeight;
	}

	public String getFileSize(File myfile)
	{
		Map vars = (Map)fileVariables.get(resolveRealFile(myfile));
		long myFileSize = ((Long)vars.get("fileSize")).longValue();

		if( myFileSize >= 1024*1024 )
			return( ((double)((int)(myFileSize/10000))/100) + "MB");
		else
			return( (myFileSize / 1024) + "KB");
	}

	public File getMovieThumbnailFile(File file)
	{
		File thumbnailFile = new File(imageDirectory, getFileName(file) + Constants.SKIN_MOVIE_THUMBNAIL_EXTENSION);

		if( thumbnailFile.exists() )
			return thumbnailFile;
		else
			return null;
	}

	public String getCopyrightContent()
	{
		return readUserVariableAsString(Constants.USER_VAR_COPYRIGHT_NOTE, imageDirectory, null);
	}

	public String getFooterContent()
	{
		return getFooterContent(null, false);
	}

	public String getFooterContent(File dir, boolean tooltip)
	{
		Map vars = getVariableContainer(dir);
		String cache_key = Constants.CACHE_KEY_PREFIX + Constants.META_FOLDER_FOOTER + tooltip;

		if( !vars.containsKey(cache_key) )
			vars.put(cache_key, getFooterContentImpl(dir, tooltip));

		return (String)vars.get(cache_key);
	}

	public String getFooterContentImpl(File dir, boolean tooltip)
	{
		File footer_file = new File((dir!=null) ? dir : imageDirectory, "footer.inc");
		String footer_content = null;

		if( footer_file.exists() )
			footer_content = readTextFile(footer_file);

		return appendString(footer_content, readFromFolderMetadata(Constants.META_FOLDER_FOOTER, dir), tooltip);
	}

	public String getSlideTitle(File myfile)
	{
		Map vars = getVariableContainer(myfile);
		String cache_key = Constants.CACHE_KEY_PREFIX + Constants.META_SLIDE_TITLE;

		if( !vars.containsKey(cache_key) )
			vars.put(cache_key, getSlideTitleImpl(myfile));

		return (String)vars.get(cache_key);
	}

	private String getSlideTitleImpl(File myfile)
	{
		String slide_title = readFromFolderMetadata(Constants.META_SLIDE_TITLE+getFileName(myfile), imageDirectory);

		if( isEmptyString(slide_title) )
			slide_title = getLabel(myfile);

		return slide_title;
	}

	public String getDirectoryTitle(File dir)
	{
		Map vars = getVariableContainer(dir);
		String cache_key = Constants.CACHE_KEY_PREFIX + Constants.META_FOLDER_TITLE;

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

		return (String)vars.get(cache_key);
	}

	private String getDirectoryTitleImpl(File dir)
	{
		String dir_title = readFromFolderMetadata(Constants.META_FOLDER_TITLE, dir);

		if( isEmptyString(dir_title) )
		{
			if( dir!=null )
			{
				Map vars = (Map)fileVariables.get(dir);

				if( vars!=null )
					dir_title = (String) vars.get("label");
				else // Top level directory!
				{
					dir_title = getAlbumTitle();

					if( isEmptyString(dir_title) )
						dir_title = rootOutputDirectory.getName();//dir.getName();
				}
			}
			else
				dir_title = (String)engine.getSkinVariables().get("title");//title;
		}

		return dir_title;
	}

	public String getAlbumTitle()
	{
		String albumTitle = (String)engine.getSkinVariables().get("title");//title;

		if( albumTitle==null )
			albumTitle = (String)album.get("rootName");

		return albumTitle;
	}

	public String getAlbumPageTitlePrefix()
	{
		String album_title = getAlbumTitle();

		if( !isEmptyString(album_title) )
			return album_title + " - ";
		else
			return "";
	}

	protected String getFrameBlock(String display_path, String link_path, boolean target_new_window, String tooltip, Dimension display_size, boolean apply_size_on_display)
	{
		StringBuffer template = new StringBuffer();
		String linkExtraParameters = target_new_window ? " target=\"_blank\"" : null;
		String imageExtraParameters = apply_size_on_display ? (" width=\"" + display_size.width + "\" height=\"" + display_size.height + "\"") : null;

		template.append("<div>");
		template.append( getActionBlock(link_path, linkExtraParameters, tooltip, display_path, imageExtraParameters) );
		template.append("</div>\n");
		return template.toString();
	}

	protected String getMovieBlock(String display_path, Dimension display_size)
	{
		Object[] args = new Object[] {display_path, new Integer(display_size.width), new Integer(display_size.height)};

		return MessageFormat.format(MOVIE_BLOCK_TEMPLATE, args);
	}

	public String getActionBlock(String targetUrl, String label, String imagePath)
	{
		return getActionBlock(targetUrl, null, label, imagePath, null);
	}

	public String getActionBlock(String hyperLink, String hyperLinkExtraParameters, String tooltip, String imagePath, String imageExtraParameters)
	{
		StringBuffer block = new StringBuffer();

		if( isEmptyString(tooltip) )
			tooltip = "&nbsp;";

		if( !isEmptyString(hyperLink) )
		{
			block.append("<a href=\"" + hyperLink + "\"");
			if( hasToolTip() )
				block.append(" title=\"" + tooltip + "\"");
			if( !isEmptyString(hyperLinkExtraParameters) )
				block.append(" " + hyperLinkExtraParameters);
			block.append(">");
		}

		block.append("<img src=\"" + imagePath + "\" border=\"0\"");
		if( hasToolTip() )
			block.append(" alt=\"" + tooltip + "\"");

		if( hasStatusBar() )
			block.append(" onmouseover=\"setStatusbarTip('" + tooltip + "', 0);\" onmouseout=\"setStatusbarTip('&nbsp;',0);\"");

		if( !isEmptyString(imageExtraParameters) )
			block.append(" " + imageExtraParameters);

		if( !isEmptyString(hyperLink) )
			block.append("/></a>");
		else
		{
			if( hasToolTip() )
				block.append("title=\"" + tooltip + "\"");
			block.append("/>");
		}

		return block.toString();
	}

	public String getExternalHomePath(boolean slide_page)
	{
		String external_home = readUserVariableAsString(Constants.USER_VAR_EXTERNAL_HOME_PATH, imageDirectory, null);

		if( external_home!=null )
		{
			external_home = external_home.trim();

			if( external_home.toLowerCase().startsWith("http:") || external_home.toLowerCase().startsWith("https:") ||
				external_home.toLowerCase().startsWith("ftp:") || external_home.toLowerCase().startsWith("ftps:") ||
				external_home.toLowerCase().startsWith("mailto:") || external_home.startsWith("/") )
				return external_home;
			else
			{
				String validRootPath = rootPath;

				if( isEmptyString(validRootPath) )
					validRootPath = ".";
				return (slide_page ? "../" : "") + validRootPath + "/" + external_home;
			}
		}

		return null;
	}

	public boolean hasStatusBar()
	{
		String helpStyle = readUserVariableAsString(Constants.USER_VAR_CONTEXT_HELP_STYLE, imageDirectory, Constants.DEFAULT_CONTEXT_HELP_STYLE);

		return( helpStyle.equalsIgnoreCase("statusbar") || helpStyle.equalsIgnoreCase("both") );
	}

	public boolean hasToolTip()
	{
		String helpStyle = readUserVariableAsString(Constants.USER_VAR_CONTEXT_HELP_STYLE, imageDirectory, Constants.DEFAULT_CONTEXT_HELP_STYLE);

		return( helpStyle.equalsIgnoreCase("tooltip") || helpStyle.equalsIgnoreCase("both") );
	}

	public boolean hasTopNavigationBar()
	{
		String navigationBar = readUserVariableAsString(Constants.USER_VAR_NAVIGATION_BAR_VERTICAL_LOCATION, imageDirectory, Constants.DEFAULT_NAVIGATION_BAR_VERTICAL_LOCATION);

		return( navigationBar.equalsIgnoreCase("Top") || navigationBar.equalsIgnoreCase("Both") );
	}

	public boolean hasBottomNavigationBar()
	{
		String navigationBar = readUserVariableAsString(Constants.USER_VAR_NAVIGATION_BAR_VERTICAL_LOCATION, imageDirectory, Constants.DEFAULT_NAVIGATION_BAR_VERTICAL_LOCATION);

		return( navigationBar.equalsIgnoreCase("Bottom") || navigationBar.equalsIgnoreCase("Both") );
	}

	public boolean hasJumpFacility()
	{
		return /*totalIndexes!=void &&*/ isVariableValueEqual( Constants.USER_VAR_INCLUDE_JUMP_TO_PAGE_ACTION, imageDirectory, true );
	}

	public int getMaximumFolderLengthOnTopPathBar()
	{
		if( isVariableValueEqual( Constants.USER_VAR_ENABLE_TEXT_TRUNCATION, imageDirectory, false ) )
			return -1;

		return readUserVariableAsInteger( Constants.USER_VAR_MAXIMUM_FOLDER_LENGTH_ON_PATH_BAR, imageDirectory, -1);
	}

	public String getHelpTips()
	{
		if( !album.containsKey(Constants.CACHE_KEY_NAVIGATION_HELP_TIPS) )
			album.put(Constants.CACHE_KEY_NAVIGATION_HELP_TIPS, getHelpTipsImpl());

		return (String) album.get(Constants.CACHE_KEY_NAVIGATION_HELP_TIPS);
	}

	private String getHelpTipsImpl()
	{
		StringBuffer buffer = new StringBuffer();

		buffer.append("<tr><td height=\"20\" valign=\"top\" colspan=\"3\"><b>" + texts.getString("nav-tips") + "</b></td></tr>\n");

		appendShortcut(buffer, "RIGHT Arrow", texts.getString("right-arrow-desc"));
		appendShortcut(buffer, "LEFT Arrow", texts.getString("left-arrow-desc"));
		appendShortcut(buffer, "Page UP", texts.getString("page-up-desc"));
		appendShortcut(buffer, "HOME", texts.getString("home-desc"));
		appendShortcut(buffer, "END", texts.getString("end-desc"));
		appendShortcut(buffer, "S, s", texts.getString("s-key-desc"));
		appendShortcut(buffer, "ESC", texts.getString("esc-desc"));
		appendShortcut(buffer, "I, i", texts.getString("i-key-desc"));
		appendShortcut(buffer, "H, h", texts.getString("h-key-desc"));
		return buffer.toString();
	}

	private void appendShortcut(StringBuffer buffer, String shortcut, String description)
	{
		buffer.append("<tr>");
		buffer.append("<td><b>" + shortcut + "</b></td>");
		buffer.append("<td align=\"center\" width=\"15\"><b>:</b></td>");
		buffer.append("<td>" + description + "</td>");
		buffer.append("</tr>\n");
	}

	protected File ensureParentFoldersExist( File file )
	{
		file.getParentFile().mkdirs();
		return file;
	}

	protected Dimension getAudioConsoleSize()
	{
		String size = readUserVariableAsString(Constants.USER_VAR_AUDIO_CONSOLE_DIMENSION, imageDirectory, null);

		try
		{
			Dimension console_size = new Dimension();
			int index = size.toLowerCase().indexOf("x");

			if( index<=0 || index==size.length()-1 )
				throw new IllegalArgumentException();

			console_size.width = Integer.parseInt( size.substring(0, index) );
			console_size.height = Integer.parseInt( size.substring(index+1) );
			return console_size;
		}
		catch( Exception e )
		{
			return Constants.DEFAULT_AUDIO_CONSOLE_DIMENSION;
		}
	}

	protected String replaceFileExtension(String path, String replace)
	{
		int index = path.indexOf( "." );

		if( index>=path.length() - 1 || index<=0 )
			return path + replace;

		return path.substring( 0, index ) + replace;
	}
}
