
import se.datadosen.jalbum.AlbumBean;
import se.datadosen.util.FileFilters;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.*;
import java.util.List;

public class Common extends PhotographicMetaInformation
{
	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, MediaUtils.getSupportedAudioTypes() );
	}

	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 getSlideComment(File myfile)
	{
		Map vars = getVariableContainer(myfile);

		if( !vars.containsKey(Constants.CACHE_KEY_SLIDE_COMMENT) )
			vars.put(Constants.CACHE_KEY_SLIDE_COMMENT, getSlideCommentImpl(myfile));

		return (String)vars.get(Constants.CACHE_KEY_SLIDE_COMMENT);
	}

	private String getSlideCommentImpl(File myfile)
	{
		Map vars = (Map)fileVariables.get(resolveRealFile(myfile));
		String result = "";

		if( vars.get("comment")!=null )
			result = vars.get("comment").toString();

		if( isEmptyString(result) )
		{
			File comment_file = new File(imageDirectory, getLabel(myfile)+".txt");

			if( comment_file.exists() )
				result = GeneralUtils.readTextFile(comment_file);
		}

		if( isEmptyString(result) )
			result = readFromFolderMetadata(Constants.META_SLIDE_DESCRIPTION + getFileName(myfile), imageDirectory);

		return result;
	}

	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 = GeneralUtils.appendString(result, getSlideTitle(myfile), tooltip);
			else if( token.equalsIgnoreCase("filename") )
				result = GeneralUtils.appendString(result, getFileName(myfile), tooltip);
			else if( token.equalsIgnoreCase("filetype") )
				result = GeneralUtils.appendString(result, "(" + FileFilters.getExtensionOf(myfile) + ")", tooltip);
			else if( token.equalsIgnoreCase("dimension") )
				result = GeneralUtils.appendString(result, getFileDimension(myfile, true), tooltip);
			else if( token.equalsIgnoreCase("slidedimension") )
				result = GeneralUtils.appendString(result, getFileDimension(myfile, false), tooltip);
			else if( token.equalsIgnoreCase("filesize") )
				result = GeneralUtils.appendString(result, "(" + getFileSize(myfile) + ")", tooltip);
			else if( token.equalsIgnoreCase("date") )
				result = GeneralUtils.appendString(result, getSlideDate(myfile), tooltip);
			else if( token.equalsIgnoreCase("remarkscount") )
			{
				if( shouldIncludeViewerRemarksOnIndex() )
					result = GeneralUtils.appendString(result, getViewerRemarksCount(myfile) + " " + texts.getString( "remarks-section" ), tooltip);
				else
					log( "[WARN] You've included 'RemarksCount' as part of thumbnails' information but 'Viewer Remarks' feature is OFF!" );
			}
			// internal and external comments are all old concepts! Now they're all the same and called 'comment'
			else if( token.equalsIgnoreCase("comment") || token.equalsIgnoreCase("internalcomment") || token.equalsIgnoreCase("exifcomment") || token.equalsIgnoreCase("embeddedcomment") || token.equalsIgnoreCase("externalcomment") )
				result = GeneralUtils.appendString(result, getSlideComment(myfile), tooltip);
			else if( meta!=null && meta.containsKey(token) )
				result = GeneralUtils.appendString(result, transformMetadataValue(token, meta.get(token)), " - ");
		}

		return( tooltip ? GeneralUtils.clearHtmlCode(result) : result );
	}

	protected String getViewerRemarksCount(File myfile)
	{
		return "<?php $userRemarks->setImageId(\"" + getViewerRemarksId( myfile ) + "\"); $userRemarks->showRemarksCount(); ?>";
	}

	protected String getViewerRemarksId(File myfile)
	{
		Map vars = getVariableContainer(myfile);
		File outDir = (File)vars.get("outputDirectory");
		String path = (outDir!=null) ? outDir.toString().substring( rootOutputDirectory.toString().length() ) : "";
		String viewerRemarksId = rootOutputDirectory.getName() + path;
		String label = (String)vars.get( "label" );

		viewerRemarksId = viewerRemarksId.replace( '\\', '/' );
		if( label!=null )
			viewerRemarksId += "/" + label;
		if( myfile.isDirectory() )
			viewerRemarksId += "/";
		return viewerRemarksId;
	}

	public boolean shouldIncludeViewerRemarksOnIndex()
	{
		return isVariableValueEqual( Constants.USER_VAR_INCLUDE_VIEWER_REMARKS_FEATURE_ON_FOLDERS, imageDirectory, true ) ||
				isVariableValueEqual( Constants.USER_VAR_INCLUDE_VIEWER_REMARKS_FEATURE_ON_SLIDES, imageDirectory, true );
	}

	public boolean isRemarksSectionAlwaysOpen()
	{
		String helpStyle = readUserVariableAsString(Constants.USER_VAR_REMARKS_SECTION_DISPLAY_STATUS, imageDirectory, Constants.DEFAULT_REMARKS_SECTION_DISPLAY_STATUS);

		return( helpStyle.equalsIgnoreCase("Always Open") );
	}

	public boolean isRemarksSectionOpenIfRemarksExist()
	{
		String helpStyle = readUserVariableAsString(Constants.USER_VAR_REMARKS_SECTION_DISPLAY_STATUS, imageDirectory, Constants.DEFAULT_REMARKS_SECTION_DISPLAY_STATUS);

		return( helpStyle.equalsIgnoreCase("Open if Remarks exist") );
	}

	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;

		thumbnailFile = new File(imageDirectory, getLabel(file) + ".thm"); // The format with Canon and Sony cameras on producing movies
		if( thumbnailFile.exists() )
			return thumbnailFile;

		return null;
	}

	public String getAlbumCopyrightContent()
	{
		return readUserVariableAsString(Constants.USER_VAR_ALBUM_COPYRIGHT_NOTE, imageDirectory, null);
	}

	public String getFooterContent()
	{
		return getFooterContent(imageDirectory, 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)
	{
		Map vars = (Map)fileVariables.get(dir);
		String footerContent = null;

		if( vars!=null )
			footerContent = (String)vars.get("description");

		if( isEmptyString(footerContent ) )
			footerContent = readFromFolderMetadata(Constants.META_FOLDER_FOOTER, dir);

		if( isEmptyString(footerContent ) )
		{
			File footer_file = new File((dir!=null) ? dir : imageDirectory, "footer.inc");

			if( footer_file.exists() )
				footerContent = GeneralUtils.readTextFile(footer_file);
		}

		return footerContent;
	}

	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 dirTitle;

		if( dir!=null )
		{
			Map vars = (Map)fileVariables.get(dir);

			if( vars!=null )
			{
				dirTitle = readFromFolderMetadata(Constants.META_FOLDER_TITLE, dir);

				if( isEmptyString(dirTitle ) )
					dirTitle = (String) vars.get("title");

				if( isEmptyString(dirTitle ) )
					dirTitle = (String) vars.get("label");
			}
			else // Top level directory!
			{
				dirTitle = getAlbumTitle();

				if( isEmptyString(dirTitle ) )
					dirTitle = readFromFolderMetadata(Constants.META_FOLDER_TITLE, dir);

				if( isEmptyString(dirTitle ) )
					dirTitle = rootOutputDirectory.getName();//dir.getName();
			}
		}
		else
		{
			dirTitle = GeneralUtils.convertToString(engine.getSkinVariables().get("title"));//title;

			if( isEmptyString(dirTitle ) )
				dirTitle = readFromFolderMetadata(Constants.META_FOLDER_TITLE, dir);
		}

		return dirTitle;
	}

	public String getAlbumTitle()
	{
		String albumTitle = GeneralUtils.convertToString(engine.getSkinVariables().get("title"));//title;

		if( albumTitle==null )
			albumTitle = GeneralUtils.convertToString(album.get("rootName"));

		return albumTitle;
	}

	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)};
		int index = display_path.lastIndexOf(".");
		String fileType = (index!=-1 && index<display_path.length()-1) ? display_path.substring( index+1 ) : null;

		return MessageFormat.format(MediaUtils.getVideoBlockTemplate(fileType), 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();
		boolean hasTooltip = hasToolTip() && !isEmptyString(tooltip);

		//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() && hasTooltip )
		{
			String fixedTooltip = GeneralUtils.replaceAll( tooltip, "'", "\\'" );

			block.append(" onmouseover=\"setStatusbarTip('" + fixedTooltip + "', 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 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;
		}
	}
}
