/* ======================================================================
   Parts Copyright 2006 University of Leeds, Oxford University, University of the Highlands and Islands.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

====================================================================== */

package org.bodington.servlet.facilities;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.bodington.server.BuildingServerException;
import org.bodington.server.realm.Permission;
import org.bodington.server.resources.ImageBlockResource;
import org.bodington.server.resources.Resource;
import org.bodington.servlet.Request;
import org.bodington.util.NullWriter;

/**
 * Class to handle the web interface to Image Block resources.
 * @author Colin Tatham
 */

public class ImageBlockFacility extends Facility
{
    private static Logger log = Logger.getLogger(ImageBlockFacility.class);

    public Resource newResource()
    {
        return new ImageBlockResource();
    }
    
    public boolean canCopy( Resource resource )
    {
        return true;
    }
    
    public List initResource( HttpServletRequest req, Resource new_resource )
    {
        ImageBlockResource imageblock;
        
        if ( !(new_resource instanceof ImageBlockResource) )
            throw new IllegalArgumentException( "Technical problem: An incorrect type of resource was created." );
        
        imageblock = (ImageBlockResource)new_resource;
        
        String linkHREF, altTagText, imageHeight, imageWidth;
        boolean displayTitle, displayDescription;

        if ( ((Request)req).getParameterFileName( "file" ).equals( "" ) )
        {
        	if ( req.getParameter( "sourceURL" ) == null ||
        			req.getParameter( "sourceURL" ).equalsIgnoreCase( "http://" ))
        		return Collections.singletonList( "Either a URL must be specified, or an image file uploaded" );
        }

        displayTitle = req.getParameter( "displayTitle" ) != null;
        imageblock.setDisplayTitle( displayTitle );
        
        displayDescription = req.getParameter( "displayDescription" ) != null;
        imageblock.setDisplayDescription( displayDescription );
        
        // remaining properties don't need check for null:
        
        altTagText = req.getParameter( "altTagText" ); 
        imageblock.setAltTagText( altTagText );
         
        linkHREF = req.getParameter( "linkHREF" );
        imageblock.setLinkHREF( linkHREF );
        
        imageHeight = req.getParameter( "imageHeight" );
        imageblock.setImageHeight( imageHeight );
        
        imageWidth = req.getParameter( "imageWidth" );
        imageblock.setImageWidth( imageWidth );
        
        return super.initResource(req, new_resource);
    }
    
    public boolean initResource( Resource original_resource, Resource new_resource )
    throws BuildingServerException
    {
        if ( !(new_resource instanceof ImageBlockResource) )
            throw new BuildingServerException(
                "Error: The wrong type of resource was created." );

        ImageBlockResource original = (ImageBlockResource)original_resource;
        ImageBlockResource imageblock = (ImageBlockResource)new_resource;

        // sets isDisplayTitle() and isDisplayDescription():
        imageblock.setImageBlockFlags( original.getImageBlockFlags() );
        // need to alter URL if it refers to uploaded file:
        /* TODO URLs shouldn't be relative, but gets too complex if they aren't? */
        String sourceURL = original.getSourceURL();
        String relativeURL = "./" + original.getName();
        if ( sourceURL.indexOf( relativeURL ) == 0 )
        {
            sourceURL = sourceURL.replaceAll( relativeURL, "./"
                + new_resource.getName() );
        }
        imageblock.setSourceURL( sourceURL );
        imageblock.setAltTagText( original.getAltTagText() );
        imageblock.setLinkHREF( original.getLinkHREF() );
        imageblock.setImageHeight( original.getImageHeight() );
        imageblock.setImageWidth( original.getImageWidth() );

        return true;
    }

    public List postCreate( Request breq, Resource newResource ) throws Exception
    {
        List errors = super.postCreate(breq, newResource);
        
        String file_name, sourceURL = null;
        ImageBlockResource imageblock;

        imageblock = ((ImageBlockResource)newResource);

        /*
         * If this method has been called during copying, the source URL will
         * have been set.
         */
        if ( imageblock.getSourceURL() != null )
        {
            return errors;
        }

        /* If user has chosen to upload a file: */
        file_name = breq.getParameterFileName( "file" );

        if ( file_name != null && !file_name.equals( "" ) )
        {
            PrintWriter out = new PrintWriter(new NullWriter());
            boolean completed = upload( breq, out, newResource, false );
            /* Using relative URL to make it easier when copying resource: */
            if ( !completed )
                throw new Exception( "Upload of image file failed" );

            sourceURL = "./" + newResource.getName() + "/" + file_name;
        }
        else
        {
            sourceURL = breq.getParameter( "sourceURL" );
        }

        /* TODO: sort this.... */
        if ( sourceURL == null || sourceURL.equalsIgnoreCase( "http://" )
            || sourceURL.equals( "" ) )
        {
            // return false;
            throw new Exception( "No source URL specified: " + sourceURL );
        }

        imageblock.setSourceURL( sourceURL );
        imageblock.save();

        return errors;
    }

    public void insert(Request req, PrintWriter out, String command, String insertname)
    throws ServletException, IOException
        {
        log.debug(" ImageBlockFacility insert()");
        
        if (!(req.getResource() instanceof ImageBlockResource))
        {
            String message = "Wrong type of resource found, expecting ImageBlock resource";
            log.error(message);
            return;
        }
        
        ImageBlockResource imageblock = (ImageBlockResource) req.getResource();
        
        if (command.equalsIgnoreCase("modifyproperties"))
        {
            if (req.getParameter("savesettings") != null)
            {
                // Save button has been pushed...   
                updateDisplayTitle(req, imageblock);
                updateDisplayDescription(req, imageblock);
                updateSourceURL(req, imageblock);
                updateAltTagText(req, imageblock);
                updateImageHeight(req, imageblock);
                updateImageWidth(req, imageblock);
                updateLinkHREF(req, imageblock);
                
                if (imageblock.isUnsaved())
                {
                    try
                    {
                        imageblock.save();
                    }
                    catch (BuildingServerException e)
                    {
                        log.debug( "Error updating ImageBlock resource.", e );
                    }
                }
                out.println("Settings saved.");
            }
            return;
        }
        
        if (command.equalsIgnoreCase("value"))
        {
            displayCurrentSettings(insertname, imageblock, out);
            return;
        }
        
        super.insert(req, out, command, insertname);
        }

    /** Checks the current value of the property specified, and displays it in the requesting page.
     * Used by resource modification page.
     * @param insertname The name of the property to query.
     * @param imageblock The resource whose properties are to be queried.
     * @param out Writer to write property value to browser.
     * @return Boolean confirming that the command was acted upon.
     */
    private boolean displayCurrentSettings(String insertname, ImageBlockResource imageblock, PrintWriter out)
    {
        // returns true if command was acted upon.
        if (insertname.equalsIgnoreCase("displayTitle"))
        {
            if (imageblock.isDisplayTitle()) out.print("checked");
            return true;
        }
        
        if (insertname.equalsIgnoreCase("displayDescription"))
        {
            if (imageblock.isDisplayDescription()) out.print("checked");
            return true;
        }
        
        if (insertname.equalsIgnoreCase("sourceURL"))
        {
            out.print(imageblock.getSourceURL());
            return true;
        }
        
        if (insertname.equalsIgnoreCase("altTagText"))
        {
            out.print(imageblock.getAltTagText());
            return true;
        }
        
        if (insertname.equalsIgnoreCase("imageHeight"))
        {
            if (imageblock.getImageHeight() != null)
            {
                out.print(imageblock.getImageHeight());
            }
            return true;
        }
        
        if (insertname.equalsIgnoreCase("imageWidth"))
        {
            if (imageblock.getImageWidth() != null)
            {
                out.print(imageblock.getImageWidth());
            }
            return true;
        }
        
        if (insertname.equalsIgnoreCase("linkHREF"))
        {
            if (imageblock.getLinkHREF() != null)
            {
                out.print(imageblock.getLinkHREF());
            }
            return true;
        }
        
        return false;
    }
    
    /** Updates setting which determines whether or not to display a title.
     * (Checks current setting first to avoid unecessary resource saving.)
     * @param req The incoming request.
     * @param imageblock The ImageBlock resource to modify.
     */
    private void updateDisplayTitle(Request req, ImageBlockResource imageblock)
    {
        if (req.getParameter("displayTitle") != null && !imageblock.isDisplayTitle())
        {
            imageblock.setDisplayTitle(true);
            imageblock.setUnsaved();
        }
        else if (req.getParameter("displayTitle") == null && imageblock.isDisplayTitle())
        {
            imageblock.setDisplayTitle(false);
            imageblock.setUnsaved();
        }
    }

    /** Updates setting which determines whether or not to display a description.
     * (Checks current setting first to avoid unecessary resource saving.)
     * @param req The incoming request.
     * @param imageblock The ImageBlock resource to modify.
     */
    private void updateDisplayDescription(Request req, ImageBlockResource imageblock)
    {
        if (req.getParameter("displayDescription") != null && !imageblock.isDisplayDescription())
        {
            imageblock.setDisplayDescription(true);
            imageblock.setUnsaved();
        }
        else if (req.getParameter("displayDescription") == null && imageblock.isDisplayDescription())
        {
            imageblock.setDisplayDescription(false);
            imageblock.setUnsaved();
        }
    }
    
    /** Updates the source URL of the image.
     * (Checks current setting first to avoid unecessary resource saving.)
     * @param req The incoming request.
     * @param imageblock The ImageBlock resource to modify.
     */
    private void updateSourceURL(Request req, ImageBlockResource imageblock)
    {
        if ( !req.getParameter("sourceURL").equals(imageblock.getSourceURL()) )
        {
            imageblock.setSourceURL(req.getParameter("sourceURL"));
            imageblock.setUnsaved();
        }
    }
    
    /** Updates the text to be used in the 'alt' attribute of the HTML image tag.
     * (Checks current setting first to avoid unecessary resource saving.)
     * @param req The incoming request.
     * @param imageblock The ImageBlock resource to modify.
     */
    private void updateAltTagText(Request req, ImageBlockResource imageblock)
    {
        if ( !req.getParameter("altTagText").equals(imageblock.getAltTagText()) )
        {
            imageblock.setAltTagText(req.getParameter("altTagText"));
            imageblock.setUnsaved();
        }
    }
    
    /** Updates the value to be used in the 'height' attribute of the HTML image tag.
     * (Checks current setting first to avoid unecessary resource saving.)
     * @param req The incoming request.
     * @param imageblock The ImageBlock resource to modify.
     */
    private void updateImageHeight(Request req, ImageBlockResource imageblock)
    {
        if ( !req.getParameter("imageHeight").equals(imageblock.getImageHeight()) )
        {
            imageblock.setImageHeight(req.getParameter("imageHeight"));
            imageblock.setUnsaved();
        }
    }
    
    /** Updates the value of the 'width' attribute of the HTML image tag.
     * (Checks current setting first to avoid unecessary resource saving.)
     * @param req The incoming request.
     * @param imageblock The ImageBlock resource to modify.
     */
    private void updateImageWidth(Request req, ImageBlockResource imageblock)
    {
        if ( !req.getParameter("imageWidth").equals(imageblock.getImageWidth()) )
        {
            imageblock.setImageWidth(req.getParameter("imageWidth"));
            imageblock.setUnsaved();
        }
    }
    
    /** Updates the URL to be linked to if the image is to act as a link.
     * (Checks current setting first to avoid unecessary resource saving.)
     * @param req The incoming request.
     * @param imageblock The ImageBlock resource to modify.
     */
    private void updateLinkHREF(Request req, ImageBlockResource imageblock)
    {
        if ( !req.getParameter("linkHREF").equals(imageblock.getLinkHREF()) )
        {
            imageblock.setLinkHREF(req.getParameter("linkHREF"));
            imageblock.setUnsaved();
        }
    }
    
    protected void resourceMenuItem(Resource resource, Request breq,
        PrintWriter out, ResourceMenuOutputState state, int depth, int highlight)
        throws IOException, BuildingServerException
    {
        String title, resource_href, target;
        String description;
        boolean manage;

        ImageBlockResource imageblock = (ImageBlockResource)resource;

        manage = resource.checkPermission(Permission.MANAGE);

        resource_href = (!state.rootless && depth == 1) ? null : (breq.getContextPath()
            + breq.getServletPath() + resource.getFullName());

        target = "_top";

        // heading level for title line matches depth but there are only
        // six heading levels in HTML so stop there.
        int hlevel = (depth > 6) ? 6 : depth;
        int level = ((depth - 1) % 10) + 1;

        // title in heading with appropriate class attribute
        out.print("          <h");
        out.print(hlevel);

        /* TODO:
         *  - Create CSS class for imageblock display?.
         */
        out.print(" class=\"" + state.css_class_prefix
            + "_heading_node_title\">");

        if ( imageblock.isDisplayTitle() )
        {
            title = imageblock.getTitle();
            out.print("<strong>");
            out.print(title);
            out.print("</strong>");
        }

        if (resource_href != null && manage)
        {
            out.print("&nbsp;<a");
            if (target != null)
            {
                out.print(" target=\"");
                out.print(target);
                out.print("\"");
            }
            out.print(" href=\"");
            out.print(resource_href);
            out.print("\" title=\"Manage Image.\"><span style=\"font-size: x-small\"><sup>Manage</sup></span></a>");
        }
        
        out.print("</h"); // end of node_title
        out.print(hlevel);
        out.println(">");

        out.print("<div class=\"" + state.css_class_prefix + "_node_content");

        if (depth == 1)
        {// was commented out in orig code??
            out.print("_without_stalk");
        }
        out.print("_lev");
        out.print(level);
        out.print("_hl");
        out.print(highlight);
        out.print("\">");
        
        // image display code
        // output anchor tag if image is to be a link:
        if (imageblock.isLink())
        {
            out.print("<a href=\"");
            out.print( imageblock.getLinkHREF() );
            out.print("\"");
            out.print(">");
        }
        // image tag:
        out.print("<img src=\"");
        out.print( imageblock.getSourceURL() );
        out.print("\" alt=\"");
        out.print( imageblock.getAltTagText() );
        out.print("\"");
        
        if ( imageblock.getImageHeight() != null )
        {
            out.print(" height=\"");
            out.print( imageblock.getImageHeight() );
            out.print("\"");
        }
        
        if ( imageblock.getImageWidth() != null )
        {
            out.print(" width=\"");
            out.print( imageblock.getImageWidth() );
            out.print("\"");
        }
        
        out.print(" />");
        
        // close anchor tag:
        if (imageblock.isLink())
        {
            out.print("</a>");
        }
        
        if ( imageblock.isDisplayDescription() )
        {
            out.print("<br />");
            description = imageblock.getDescription(); // could return null...
            out.print(description);
        }
        
        String markup = timedResourceText(resource);
        if (markup != null)
            out.print("<div>" + markup + "</div>");

        out.print("</div>");
        out.print( "<div class=\"clearer\">&nbsp;</div>\n");
    }

    public boolean isResourceAtDefaultURL()
    {
        return false;
    }
}
