/**
 * Copyright (c) 2008-2009, Aberystwyth University
 *
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met:
 * 
 *  - Redistributions of source code must retain the above 
 *    copyright notice, this list of conditions and the 
 *    following disclaimer.
 *  
 *  - Redistributions in binary form must reproduce the above copyright 
 *    notice, this list of conditions and the following disclaimer in 
 *    the documentation and/or other materials provided with the 
 *    distribution.
 *    
 *  - Neither the name of the Centre for Advanced Software and 
 *    Intelligent Systems (CASIS) nor the names of its 
 *    contributors may be used to endorse or promote products derived 
 *    from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 * SUCH DAMAGE.
 */
package org.purl.sword.base;

import java.util.ArrayList;
import java.util.Properties;
import nu.xom.Attribute;
import nu.xom.Element;

import org.apache.log4j.Logger;
import org.purl.sword.atom.Author;
import org.purl.sword.atom.Title;

/**
 * Extension of the SWORD Entry class, specialized for Error Documents. 
 * 
 * @author Stuart Lewis (sdl@aber.ac.uk)
 * @author Neil Taylor (nst@aber.ac.uk)
 */ 
public class SWORDErrorDocument extends SWORDEntry
{
	/**
	* Local name for the element. 
	*/
   @Deprecated
   public static final String ELEMENT_NAME = "error";
   
   /**
    * The logger.
    */
   private static Logger log = Logger.getLogger(SWORDErrorDocument.class);

   private static final XmlName XML_NAME =
           new XmlName(Namespaces.PREFIX_SWORD, "error", Namespaces.NS_SWORD);

   private static final XmlName ATTRIBUTE_HREF_NAME =
           new XmlName(Namespaces.PREFIX_SWORD, "href", Namespaces.NS_SWORD);

   /**
    * The Error URI
    */
   private String errorURI;

   /**
    * Create the error document (intended to be used when unmarshalling an error document
    * as this will set the errorURI)
    */
   public SWORDErrorDocument() {
	   super(XML_NAME.getPrefix(),
             XML_NAME.getLocalName(),
             XML_NAME.getNamespace());
   }

   /**
    * Create the error document
    * 
    * @param errorURI The URI of the error
    */
   public SWORDErrorDocument(String errorURI) {
	   this();
	   this.errorURI = errorURI;
   }

   /**
    * Get the element name.
    * 
    * @return
    */
   public static XmlName elementName()
   {
      return XML_NAME; 
   }

   /**
    * 
    */
   protected void initialise()
   {
       super.initialise();
   }
   
   /**
    * Overrides the marshall method in the parent SWORDEntry. This will 
    * call the parent marshall method and then add the additional 
    * elements that have been added in this subclass.  
    */
   public Element marshall()
   {
	   Element entry = new Element(getQualifiedName(), Namespaces.NS_SWORD);
	   entry.addNamespaceDeclaration(Namespaces.PREFIX_SWORD, Namespaces.NS_SWORD);
	   entry.addNamespaceDeclaration(Namespaces.PREFIX_ATOM, Namespaces.NS_ATOM);
	   Attribute error = new Attribute("href", errorURI);
       entry.addAttribute(error);
	   super.marshallElements(entry);
       return entry;
   }

   /**
    * Overrides the unmarshall method in the parent SWORDEntry. This will 
    * call the parent method to parse the general Atom elements and
    * attributes. This method will then parse the remaining sword
    * extensions that exist in the element. 
    * 
    * @param entry The entry to parse. 
    * 
    * @throws UnmarshallException If the entry is not an atom:entry 
    *              or if there is an exception extracting the data. 
    */
   public void unmarshall(Element entry) throws UnmarshallException
   {
       unmarshall(entry, null);
   }

   /**
    * 
    * @param entry
    * @param validationProperties
    * @return
    * @throws org.purl.sword.base.UnmarshallException
    */
   public SwordValidationInfo unmarshall(Element entry, Properties validationProperties)
   throws UnmarshallException
   {
      SwordValidationInfo result = super.unmarshall(entry, validationProperties);
      result.clearValidationItems();

      errorURI = entry.getAttributeValue(ATTRIBUTE_HREF_NAME.getLocalName());
      
      if( validationProperties != null )
      {
         result = validate(result, validationProperties);
      }
      
      return result;
   }

   /**
    * This method overrides the XmlElement definition so that it can allow
    * the definition of the href attribute. All other attributes are
    * shown as 'Unknown Attribute' info elements.
    *
    * @param element The element that contains the attributes
    * @param info    The info object that will hold the validation info. 
    */
   @Override
   protected void processUnexpectedAttributes(Element element, SwordValidationInfo info)
   {
       int attributeCount = element.getAttributeCount();
       Attribute attribute = null;

       for( int i = 0; i < attributeCount; i++ )
       {
            attribute = element.getAttribute(i);
            if( ! ATTRIBUTE_HREF_NAME.getLocalName().equals(attribute.getQualifiedName()) )
            {

               XmlName attributeName = new XmlName(attribute.getNamespacePrefix(),
                       attribute.getLocalName(),
                       attribute.getNamespaceURI());

               SwordValidationInfo item = new SwordValidationInfo(xmlName, attributeName,
                       SwordValidationInfo.UNKNOWN_ATTRIBUTE,
                       SwordValidationInfoType.INFO);
               item.setContentDescription(attribute.getValue());
               info.addUnmarshallAttributeInfo(item);
            }
       }
   }

   /**
    *
    * @param elementName
    * @return
    */
   protected boolean isElementChecked(XmlName elementName)
   {
       return super.isElementChecked(elementName);
   }

   /**
    *
    * @return
    */
   public SwordValidationInfo validate(Properties validationContext)
   {
       return validate(null, validationContext);
   }

   /**
    * 
    * @param elements
    * @param attributes
    * @return
    */
   protected SwordValidationInfo validate(SwordValidationInfo info, Properties validationContext)
   {
      
      if( errorURI == null )
      {
         info.addValidationInfo(new SwordValidationInfo(xmlName, ATTRIBUTE_HREF_NAME,
                 SwordValidationInfo.MISSING_ATTRIBUTE_WARNING,
                 SwordValidationInfoType.WARNING));
      }
      else
      {
         boolean validUri = true;
         if(errorURI.startsWith("http://purl.org/net/sword/error/"))
         {
             // check that the list of codes
             if( ! (errorURI.equals(ErrorCodes.ERROR_CONTENT) ||
                    errorURI.equals(ErrorCodes.ERROR_CHECKSUM_MISMATCH) ||
                    errorURI.equals(ErrorCodes.ERROR_BAD_REQUEST) ||
                    errorURI.equals(ErrorCodes.TARGET_OWNER_UKNOWN) ||
                    errorURI.equals(ErrorCodes.MEDIATION_NOT_ALLOWED)) )
             {
                 info.addValidationInfo(new SwordValidationInfo(xmlName,
                         ATTRIBUTE_HREF_NAME,
                         "Errors in the SWORD namespace are reserved and legal values are enumerated in the SWORD 1.3 specification. Implementations MAY define their own errors, but MUST use a different namespace to do so.",
                         SwordValidationInfoType.ERROR));
                 validUri = false; 
             }
         }

         if( validUri )
         {
             SwordValidationInfo item = new SwordValidationInfo(xmlName, ATTRIBUTE_HREF_NAME);
             item.setContentDescription(errorURI);
             info.addAttributeValidationInfo(item);
         }
      }
      return info; 
   }

   
   /**
    * Get the error URI
    * 
    * @return the error URI
    */
   public String getErrorURI()
   {
       return errorURI;
   }

   /**
    * set the error URI
    * 
    * @param error the error URI
    */
   public void setErrorURI(String error)
   {
       errorURI = error;
   }

   /**
    * Main method to perform a brief test of the class
    * 
    * @param args
    */
   /*public static void main(String[] args)
   {
	   SWORDErrorDocumentTest sed = new SWORDErrorDocumentTest(ErrorCodes.MEDIATION_NOT_ALLOWED);
	   sed.setNoOp(true);
	   sed.setTreatment("Short back and shine");
	   sed.setId("123456789");
	   Title t = new Title();
	   t.setContent("My first book");
	   sed.setTitle(t);
	   Author a = new Author();
	   a.setName("Lewis, Stuart");
	   a.setEmail("stuart@example.com");
	   sed.addAuthors(a);
	   
	   System.out.println(sed.marshall().toXML());
   }
    */
}