package com.k_int.aggr2.mimsy.data;

import java.awt.RenderingHints;
import java.awt.image.renderable.ParameterBlock;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.media.jai.JAI;
import javax.media.jai.OpImage;
import javax.media.jai.RenderedOp;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.k_int.aggr2.mimsy.data.hdo.ValidationResultHDO;
import com.k_int.mimsy.ref.DataStatusEnum;
import com.k_int.mimsy.ref.MediaRecordTypeEnum;
import com.k_int.mimsy.ref.ObjectConformanceEnum;
import com.k_int.mimsy.ref.ValidationMessages;
import com.k_int.mimsy.ref.ValidationStatusEnum;
import com.sun.media.jai.codec.SeekableStream;

public class MimsyObjectValidator 
{
	public static int MAX_HEIGHT_LARGE	= 400;
	public static int MAX_WIDTH_PREVIEW	= 104;
	public static int MAX_WIDTH_MID		= 155;
	public static int MAX_WIDTH_LARGE	= 333;
	
	public static int GROUP_IMAGE_WIDTH	= 538;
	public static int GROUP_IMAGE_HEIGHT= 322;
	
	private static Log log = LogFactory.getLog(MimsyObjectValidator.class);
	
	
	public static ValidationResultHDO validate(MimsyObjectDataDTO data)
	{
		ValidationResultHDO result = null;
		
		if(data.getConformance()==ObjectConformanceEnum.CORE)
			result=validateCoreFields(data,true,ObjectConformanceEnum.CORE);
		else if (data.getConformance()==ObjectConformanceEnum.EXTENDED_1)
		{
			result=validateExtended1Fields(data,true,ObjectConformanceEnum.EXTENDED_1);
		}
		else if (data.getConformance()==ObjectConformanceEnum.EXTENDED_2)
		{
			result=validateExtended2Fields(data,true,ObjectConformanceEnum.EXTENDED_2);
		}
		else if (data.getConformance()==ObjectConformanceEnum.EXTENDED_3)
		{
			result=validateExtended3Fields(data,true,ObjectConformanceEnum.EXTENDED_3);	
		}
		else if (data.getConformance()==ObjectConformanceEnum.ORAL_HISTORY_CORE)
			result=validateCoreOralHistory(data,true,ObjectConformanceEnum.ORAL_HISTORY_CORE);	
		else if (data.getConformance()==ObjectConformanceEnum.ORAL_HISTORY_EXTENDED_1)
			result=validateExtended1OralHistory(data,true,ObjectConformanceEnum.ORAL_HISTORY_EXTENDED_1);	
		else if (data.getConformance()==ObjectConformanceEnum.ORAL_HISTORY_EXTENDED_2)
			result=validateExtended2OralHistory(data,true,ObjectConformanceEnum.ORAL_HISTORY_EXTENDED_2);
		else if (data.getConformance()==ObjectConformanceEnum.ORAL_HISTORY_EXTENDED_3)
			result=validateExtended3OralHistory(data,true,ObjectConformanceEnum.ORAL_HISTORY_EXTENDED_3);	
		
		return result;
	}
	
	private static ValidationResultHDO validateCoreOralHistory(MimsyObjectDataDTO data, boolean remove_non_conformant, ObjectConformanceEnum conformance)
	{
		ValidationResultHDO result = new ValidationResultHDO(data,conformance);
		
		Object check = data.getMimsyIdentifier();
		if(check==null)
			result.addError("mimsyIdentifier", ValidationMessages.IS_MISSING);
		
		check = data.getRecordType();
		
		if(check==null)
			result.addError("recordType", ValidationMessages.IS_MISSING);
			
		
		check = data.getItemCount();
		
		if(check==null)
			result.addError("itemCount", ValidationMessages.IS_MISSING);
		
		check = data.getSection();
		
		if(check==null)
			result.addError("section", ValidationMessages.IS_MISSING);
		
		
		if(data.getNames().size()==0)
			result.addError("name", ValidationMessages.IS_MISSING);
		else
		{
			int j = data.getNames().size();
			Iterator<NameDTO> i = data.getNames().iterator();
			while(i.hasNext())
			{
				NameDTO name = i.next();
				if(name.getType()==null)
					i.remove();
			}
			if(data.getNames().size()==0)
				result.addError("name", ValidationMessages.NAMES_HAVE_NO_TYPES);
			else if (data.getNames().size()<j)
			{
				result.addMessage("name", ValidationMessages.NAMES_HAVE_MISSING_TYPES);
			}
		}
		
		check = data.getTitle();
		
		if(check==null)
			result.addError("title", ValidationMessages.IS_MISSING);
		
		if(data.getLinkedMakers().size()==0)
		{
			//result.addError("makers", ValidationMessages.IS_MISSING);
			// removed 1/11/10
		}
		else
		{
			Iterator<ControlledReferenceDTO> i = data.getLinkedMakers().iterator();
			int counter=1;
			while(i.hasNext())
			{
				ControlledReferenceDTO ref = i.next();
				if(ref.getIdentifier()==null)
					result.addError("makerLink."+counter+".identifier", ValidationMessages.IS_MISSING);
				
				if(ref.getRelationship()==null)
					result.addError("makerLink."+counter+".relationship", ValidationMessages.IS_MISSING);
				
				counter++;
			}
		}
		
		if(data.getMadeDates().size()==0)
			result.addError("datesMade", ValidationMessages.IS_MISSING);
		else
		{
			int counter=1;
			Iterator<MimsyDateDTO> i = data.getMadeDates().iterator();
			while(i.hasNext())
			{
				MimsyDateDTO date = i.next();
				
				//if(date.getDateText()==null)
				//	result.addError("dateMade."+counter+".date",ValidationMessages.IS_MISSING);
				
				if(date.getEarliest()==null)
					result.addError("dateMade."+counter+".earliest", ValidationMessages.IS_MISSING);
				
				if(date.getLatest()==null)
					result.addError("dateMade."+counter+".latest", ValidationMessages.IS_MISSING);
				counter++;
			}
		}
				
		
		check=data.getSummary();
		if(check==null)
			result.addError("summary", ValidationMessages.IS_MISSING);
		
		check=data.getIntendedUse();
		if(check==null)
			result.addError("intendedUse", ValidationMessages.IS_MISSING);
		
		if(data.getProjectCodes().size()==0)
			result.addError("projectCode", ValidationMessages.IS_MISSING);

		removeSurplusIntreuctions(data.getInstructions());
		
		if(data.getInstructions().size()==0)
			result.addError("instructions", "no valid instructions");

		if(data.getRights()==null)
			result.addError("rights",ValidationMessages.IS_MISSING);
		else
		{		
			RightsDTO rights = data.getRights();
			check=rights.getHolder();
			if(check==null)
				result.addError("rights.holder",ValidationMessages.IS_MISSING);
			
			check=rights.getType();
			if(check==null)
				result.addError("rights.type",ValidationMessages.IS_MISSING);	
			
		}
		
		if(remove_non_conformant)
		{
			data.getOtherNumbers().clear();
			data.getOtherTitles().clear();
			data.setPagination(null);
			data.setPublisher(null);
			data.setPlaceMade(null);
			data.setPlaceCollected(null);
			data.getMaterials().clear();
			data.setMeasurements(null);			
			data.getLinkedCollectors().clear();
			data.getCollectedDates().clear();
			data.setSite(null);			
			data.getDescriptions().clear();
			data.setAcquisition(null);
			data.setOwnerStatus(null);
			data.setCurrentLocation(null);
			data.setPermanentLocation(null);
			data.setLoanAllowed(null);
			data.setNote(null);			
			data.setConservationAction(null);
			data.getLinkedObjects().clear();		
			data.setAdditionalInformation(null);
					
			Iterator<MimsyDateDTO> i = data.getMadeDates().iterator();
			while(i.hasNext())
			{
				MimsyDateDTO date = i.next();			
				date.setAttribution(null);
				date.setEra(null);
				date.setMethod(null);
				date.setRelation(null);			
			}
		}
			
		return result;
	}
	
	private static ValidationResultHDO validateExtended1OralHistory(MimsyObjectDataDTO data, boolean remove_non_conformant, ObjectConformanceEnum conformance)
	{
		ValidationResultHDO result = validateCoreOralHistory(data,false,conformance);
	
		Iterator<MimsyDateDTO> i = data.getMadeDates().iterator();
		int counter=1;
		while(i.hasNext()) // others validated in core
		{
			MimsyDateDTO date = i.next();
		
			if(date.getRelation()==null)
				result.addError("dateMade."+counter+".relation",ValidationMessages.IS_MISSING);
			counter++;
		}
		
		//Object check = data.getMeasurements();
		//if(check==null)
		//	result.addError("measurements",ValidationMessages.IS_MISSING);
		
		
		if(data.getDescriptions().size()==0)
			result.addError("descriptions",ValidationMessages.IS_MISSING);
		else
		{
			counter=1;
			Iterator<DescriptionDTO> d = data.getDescriptions().iterator();
			while(d.hasNext())
			{
				DescriptionDTO desc = d.next();
				
				if(desc.getType()==null)
					result.addError("description"+counter+".type",ValidationMessages.IS_MISSING);
				
				if(desc.getSource()==null)
					result.addError("description"+counter+".source",ValidationMessages.IS_MISSING);
				
				if(desc.getDate()==null)
					result.addError("description"+counter+".date",ValidationMessages.IS_MISSING);
				
				if(desc.getDescription()==null)
					result.addError("description"+counter+".description",ValidationMessages.IS_MISSING);
				counter++;
			}
		}
		
		Object check = data.getAcquisition();
		if(check==null)
			result.addError("acquisition",ValidationMessages.IS_MISSING);
		
		
		if(data.getLinkedMedia().size()==0)
			result.addError("media",ValidationMessages.IS_MISSING);
			
		if(result.getStatus()==ValidationStatusEnum.INVALID)
		{
			ValidationResultHDO core_result=validateCoreOralHistory(data, false, ObjectConformanceEnum.ORAL_HISTORY_CORE);
			
			if(core_result.getStatus()==ValidationStatusEnum.VALID)
			{
				result = validateCoreFields(data,true, ObjectConformanceEnum.ORAL_HISTORY_CORE);
				data.setConformance(ObjectConformanceEnum.ORAL_HISTORY_CORE);
			}
		}	
		
		
		if(remove_non_conformant)
		{
			data.getOtherNumbers().clear();
			data.getOtherTitles().clear();
			data.setPagination(null);
			data.setPublisher(null);
			data.setPlaceMade(null);
			data.setPlaceCollected(null);
			data.getMaterials().clear();;			
			data.getLinkedCollectors().clear();
			data.getCollectedDates().clear();
			data.setSite(null);			
		
			data.setOwnerStatus(null);
			data.setCurrentLocation(null);
			data.setPermanentLocation(null);
			data.setLoanAllowed(null);
			data.setNote(null);			
			data.setConservationAction(null);
			data.getLinkedObjects().clear();		
			data.setAdditionalInformation(null);
			
			Iterator<MimsyDateDTO> j = data.getMadeDates().iterator();
			while(j.hasNext())
			{
				MimsyDateDTO date = j.next();			
				date.setAttribution(null);
				date.setEra(null);
				date.setMethod(null);				
			}
			
			RightsDTO rights = data.getRights();
			if(rights!=null)	
			{
				rights.setCreditLine(null)	;
				rights.setDetails(null);
				rights.setFromDate(null);
				rights.setToDate(null);
			}
			
		}
	
		return result;
	}
	
	private static ValidationResultHDO validateExtended2OralHistory(MimsyObjectDataDTO data, boolean remove_non_conformant, ObjectConformanceEnum conformance)
	{
		ValidationResultHDO result = validateExtended1Fields(data,false,conformance);
		// now add the others
		return result;
	}
	
	private static ValidationResultHDO validateExtended3OralHistory(MimsyObjectDataDTO data, boolean remove_non_conformant, ObjectConformanceEnum conformance)
	{
		ValidationResultHDO result = validateExtended2Fields(data,false,conformance);
		// now add the others
		return result;
	}
	
	private static ValidationResultHDO validateCoreFields(MimsyObjectDataDTO data, boolean remove_non_conformant, ObjectConformanceEnum conformance)
	{
		ValidationResultHDO result = new ValidationResultHDO(data,conformance);
		
		
		Object check = data.getMimsyIdentifier();
		if(check==null)
			result.addError("mimsyIdentifier",ValidationMessages.IS_MISSING);
		
		check = data.getRecordType();
		
		if(check==null)
			result.addError("recordType",ValidationMessages.IS_MISSING);
		
		check = data.getItemCount();
		
		if(check==null)
			result.addError("itemCount",ValidationMessages.IS_MISSING);
		
		check = data.getSection();
		
		if(check==null)
			result.addError("section",ValidationMessages.IS_MISSING);
		
		if(data.getNames().size()==0)
			result.addError("name", ValidationMessages.IS_MISSING);
		else
		{
			int j = data.getNames().size();
			Iterator<NameDTO> i = data.getNames().iterator();
			while(i.hasNext())
			{
				NameDTO name = i.next();
				if(name.getType()==null)
					i.remove();
			}
			if(data.getNames().size()==0)
				result.addError("name", ValidationMessages.NAMES_HAVE_NO_TYPES);
			else if (data.getNames().size()<j)
			{
				result.addMessage("name", ValidationMessages.NAMES_HAVE_MISSING_TYPES);
			}
		}
		
		check = data.getAcquisition();
		
		if(check==null)
			result.addError("acquisition",ValidationMessages.IS_MISSING);
		
		
		check = data.getOwnerStatus();
		
		if(check==null)
			result.addError("ownerStatus",ValidationMessages.IS_MISSING);
		
		
		check = data.getPermanentLocation();
		
		//TODO dont forget current location
		
		if(check==null)
			result.addError("permanentLocation",ValidationMessages.IS_MISSING);
		
		removeSurplusIntreuctions(data.getInstructions());
		
		if(data.getInstructions().size()==0)
			result.addError("instructions", "No valid instructions");
		
		
		if(data.getRights()==null)
			result.addError("rights",ValidationMessages.IS_MISSING);
		else
		{
			
				RightsDTO rights = data.getRights();
				check=rights.getHolder();
				if(check==null)
					result.addError("rights.holder",ValidationMessages.IS_MISSING);
				
				check=rights.getType();
				if(check==null)
					result.addError("rights.type",ValidationMessages.IS_MISSING);	
			
		}
		
				
		if(remove_non_conformant)
		{
			data.getOtherNumbers().clear();
			data.getOtherTitles().clear();
			Iterator<MimsyDateDTO> i = data.getMadeDates().iterator();
			while(i.hasNext())
			{
				MimsyDateDTO date = i.next();
				
				if(date.getDateText()==null)
					i.remove();
				else
				{
					date.setAttribution(null);
					date.setEra(null);
					date.setMethod(null);
					date.setRelation(null);				
				}
			
			}
			data.getLinkedCollectors().clear();
			data.getCollectedDates().clear();
			data.setSite(null);
			data.setSummary(null);
			data.getDescriptions().clear();
			data.setLoanAllowed(null);
			data.setNote(null);
			data.setProjectNotes(null);
			data.setIntendedUse(null);
			data.setConservationAction(null);
			Iterator<ControlledReferenceDTO> j = data.getLinkedObjects().iterator();
			while(j.hasNext())
			{
				ControlledReferenceDTO ref = j.next();
				ref.setRelationship(null);
			}
			data.setAdditionalInformation(null);		
		}
			
		return result;
	}
	
	private static void removeSurplusIntreuctions(Set<InstructionDTO> instructions)
	{
		Iterator<InstructionDTO> j = instructions.iterator();
		
	
		while(j.hasNext())
		{
			InstructionDTO i = j.next();
			
			//if(i.getStatus()==null)
			if(i.getType()==null)
			{
				j.remove();
				continue;
			}
			if(i.getStatus()==null)
			{
				j.remove();
				continue;
			}
			
			String status = i.getStatus();
			
			if(status.equals("Complete") || status.equals("QA complete"))
			{;}
			else
			{
				j.remove();
				continue;
			}
			
			
			String type   = i.getType();
			
				
			if(type.equals("CCity Extended Record 1 QA") || type.equals("Collections Online Extended record 1 QA"))
			{;}
			else if (type.equals("CCity Extended Record 2 QA") || type.equals("Collections Online Extended record 2 QA"))
			{;}
			else if (type.equals("CCity Core Record QA") || type.equals("Collections Online Core record QA"))
			{;}
			else
			{
				j.remove();
				continue;
			}
				/*if(status.equals("Core record plus image") || status.equals("Core record"))
				{;}
				else if (status.equals("Extended record 1 DRAFT") || status.equals("Extended record 1"))
				{;}
				else if (status.equals("Extended record 2 DRAFT") || status.equals("Extended record 2"))
				{;}
				else
				{
					j.remove();
					continue;
				}*/
				
			if(i.getDate()==null || i.getStatus()==null || i.getType()==null)	
				j.remove();
			
		}
	
	}
	
	private static ValidationResultHDO validateExtended1Fields(MimsyObjectDataDTO data, boolean remove_non_conformant, ObjectConformanceEnum conformance)
	{		
		ValidationResultHDO result = validateCoreFields(data,false,conformance);
		
		Object check = data.getMaterials();
		if(check==null)
			result.addError("materials",ValidationMessages.IS_MISSING);
		
		//check = data.getMeasurements();
		//if(check==null)
		//	result.addError("measurements",ValidationMessages.IS_MISSING);
		
		Iterator<DescriptionDTO> i = data.getDescriptions().iterator();
		int counter=0;
		while(i.hasNext())
		{
			counter++;
			DescriptionDTO d = i.next();
			
			if(d.getType()==null)
				result.addError("description"+counter+".type",ValidationMessages.IS_MISSING);
			
			if(d.getSource()==null)
				result.addError("description"+counter+".source",ValidationMessages.IS_MISSING);
			
			if(d.getDate()==null)
				result.addError("description"+counter+".date",ValidationMessages.IS_MISSING);
			
			if(d.getDescription()==null)
				result.addError("description"+counter+".description",ValidationMessages.IS_MISSING);
		
		}
				
		if(result.getStatus()==ValidationStatusEnum.INVALID)
		{
			ValidationResultHDO core_result=validateCoreFields(data, false, ObjectConformanceEnum.CORE);
			
			if(core_result.getStatus()==ValidationStatusEnum.VALID)
			{
				result = validateCoreFields(data,true, ObjectConformanceEnum.CORE);
				data.setConformance(ObjectConformanceEnum.CORE);
			}
		}			
		if(remove_non_conformant)
		{
			data.getOtherNumbers().clear();
			/*Iterator<ControlledReferenceDTO> k = data.getLinkedMakers().iterator();
			while(k.hasNext())
			{
				ControlledReferenceDTO ref = k.next();
				ref.setRelationship(null);
			}*/	
						
			data.setNote(null);
			
			Iterator<MimsyDateDTO> m = data.getMadeDates().iterator();
			while(m.hasNext())
			{
				MimsyDateDTO date = m.next();
				
				date.setAttribution(null);
				date.setEra(null);
				date.setMethod(null);
				date.setRelation(null);
				
			}			
			m = data.getCollectedDates().iterator();
			while(m.hasNext())
			{
				MimsyDateDTO date = m.next();
				date.setAttribution(null);
				date.setEra(null);
				date.setMethod(null);	
				date.setRelation(null);
			}
		}	
		return result;
	}
	
	private static ValidationResultHDO validateExtended2Fields(MimsyObjectDataDTO data, boolean remove_non_confirmant, ObjectConformanceEnum conformance)
	{
		ValidationResultHDO result = validateExtended1Fields(data,false,conformance);
		// now add the others
		return result;
	}
	
	private static ValidationResultHDO validateExtended3Fields(MimsyObjectDataDTO data,boolean remove_non_conformant, ObjectConformanceEnum conformance)
	{
		ValidationResultHDO result = validateExtended2Fields(data,false,conformance);
		// now add the others
		return result;
	}
	
	/**private static ValidationResult validateWebReadyFields(MimsyObjectData data)
	{
		return validateCoreFields(data,true);
	}
	**/
	public static ValidationResultHDO  validateReferenceData(MimsyReferenceDataDTO data)
	{
		ValidationResultHDO retval=null;
		if(data instanceof MimsyEventDataDTO)
			retval=validateEventFields((MimsyEventDataDTO) data);
		else if (data instanceof MimsyAgentDataDTO)
			retval=validateAgentFields((MimsyAgentDataDTO) data);
		else if (data instanceof MimsyPlaceDataDTO)
			retval=validatePlaceFields((MimsyPlaceDataDTO) data);
		else if (data instanceof MimsySubjectDataDTO)
			retval=validateSubjectFields((MimsySubjectDataDTO) data);
		else if (data instanceof MimsyMediaDataDTO)
			retval=validateMediaFields((MimsyMediaDataDTO) data);
		else if (data instanceof MimsySiteDataDTO)
			retval=validateSiteFields((MimsySiteDataDTO) data);
		else if (data instanceof MimsyPublicationDataDTO)
			retval=validatePublicationFields((MimsyPublicationDataDTO) data);
		
		return retval;
	}
	
	public static ValidationResultHDO validateGroupData(MimsyCuratedGroupDTO data)
	{
		ValidationResultHDO result = new ValidationResultHDO(data,data.getConformance());
		
		String object = data.getName();
				
		if(object==null)
			result.addError("name",ValidationMessages.IS_MISSING);
		
		object=data.getPurpose();
		if(object==null)
			result.addError("purpose",ValidationMessages.IS_MISSING);
		
		object=data.getMimsyOwner();
		
		if(object==null)
			result.addError("owner",ValidationMessages.IS_MISSING);
		
		return result;
	}
	
	private static ValidationResultHDO validateSiteFields(MimsySiteDataDTO data)
	{
		ValidationResultHDO result = new ValidationResultHDO(data,data.getConformance());
	
		String object = data.getName();
		
		
		if(object==null)
			result.addError("name",ValidationMessages.IS_MISSING);
		
		object = data.getSiteYear();
		
		
		if(object==null)
			result.addError("year",ValidationMessages.IS_MISSING);
		
		object = data.getSummary();
		
		
		if(object==null)
			result.addError("summary",ValidationMessages.IS_MISSING);
		
		
		object = data.getSiteId();
		
		if(object==null)
			result.addError("siteID",ValidationMessages.IS_MISSING);
		
		object = data.getDate();
		
		
		if(object==null)
			result.addError("period/date",ValidationMessages.IS_MISSING);
		
		object = data.getLocation();
		
		
		if(object==null)
			result.addError("location",ValidationMessages.IS_MISSING);
		
		object = data.getEastings();
		
		
		if(object==null)
			result.addError("eastings",ValidationMessages.IS_MISSING);
		
		object = data.getNorthings();
		
		
		if(object==null)
			result.addError("northings",ValidationMessages.IS_MISSING);
		
		object = data.getSiteType();
		
		
		if(object==null)
			result.addError("siteType",ValidationMessages.IS_MISSING);
		
		object = data.getOrganisation();
				
		if(object==null)
			result.addError("organisation",ValidationMessages.IS_MISSING);
			
		if(data.getConformance()==ObjectConformanceEnum.EXTENDED_1)
		{
			if(data.getExcavations().size()==0)
				result.addError("excavations",ValidationMessages.IS_MISSING);
			else
			{
				Iterator<ExcavationDTO> e = data.getExcavations().iterator();
				Object check;
				int counter=0;
				while(e.hasNext())
				{
					counter++;			
					ExcavationDTO ex = e.next();
					check = ex.getEnd();
					if(check==null)
						result.addError("excavation."+counter+".end",ValidationMessages.IS_MISSING);	
					
					check=ex.getStart();
					if(check==null)
						result.addError("excavation."+counter+".begin",ValidationMessages.IS_MISSING);	
					
					check = ex.getOrganisation();
					if(check==null)
						result.addError("excavation."+counter+".organisation",ValidationMessages.IS_MISSING);	
					check = ex.getRole();
					if(check==null)
						result.addError("excavation."+counter+".role",ValidationMessages.IS_MISSING);	
					
				}
			}
			
						
		}
	
			
		if(data.getInstructions().size()==0)
			result.addError("instructions",ValidationMessages.IS_MISSING);
		else
		{
			Iterator<InstructionDTO> i = data.getInstructions().iterator();
			Object check;
			while(i.hasNext())
			{
				InstructionDTO instr = i.next();
				check = instr.getType();
				if(check==null)
					result.addError("instruction.type",ValidationMessages.IS_MISSING);
				
				check = instr.getStatus();
				if(check==null)
					result.addError("instruction.status",ValidationMessages.IS_MISSING);
				
				check = instr.getName();
				if(check==null)
					result.addError("instruction.name",ValidationMessages.IS_MISSING);
				check = instr.getDate();
				if(check==null)
					result.addError("instruction.date",ValidationMessages.IS_MISSING);
			}
		}	
	
		return result;
	}
	
	public static ValidationResultHDO validateGroupObjectContext(DataContextDTO data,Map<String,MimsyDataDTO> retval,Map<String,ValidationResultHDO> error_or_incomplete, Set<String> previously_published)
	{
		ValidationResultHDO result = new ValidationResultHDO(data,data.getConformance());
		if(data.getStatus()!=DataStatusEnum.LIVE)
		{;}
		else if(previously_published.contains(data.getMimsyDataIdentifier()))
		{;}
		else if (retval.keySet().contains(data.getMimsyDataIdentifier()))
		{;}
		else if (error_or_incomplete.keySet().contains(data.getMimsyDataIdentifier()))
		{
			if(error_or_incomplete.get(data.getMimsyDataIdentifier()).getStatus()==ValidationStatusEnum.INVALID)
				result.addError("referencedObject",data.getMimsyDataIdentifier()+ValidationMessages.NON_CONFORMANT);
		}
		else
		{
			result.addError("referencedObject",data.getMimsyDataIdentifier()+ValidationMessages.NOT_WEB_READY);
		}				
		return result;
	}
	private static ValidationResultHDO validateEventFields(MimsyEventDataDTO data)
	{
		ValidationResultHDO result = new ValidationResultHDO(data,data.getConformance());
		String name_check = data.getFullName();
		
		if(name_check==null)
			result.addError("fullName",ValidationMessages.IS_MISSING);
		else if (name_check.startsWith("DO NOT USE"))
			result.addError("fullName", "starts with do not use");
		
		
		//Object check = data.getCandidate();
		
		//if(check==null)
		//	result.addError("candidate",MISSING);
		Object check;
		if(data.getConformance()==ObjectConformanceEnum.EXTENDED_1)
		{
			check = data.getDisplayDate();
			if(check==null)
				result.addError("displayDate",ValidationMessages.IS_MISSING);
			
			check = data.getDescription();
			
			if(check==null)
				result.addError("description",ValidationMessages.IS_MISSING);
			
			check=data.getScopeNote();
			if(check==null)
				result.addError("scopeNote",ValidationMessages.IS_MISSING);
						
		}
			
		if(data.getInstructions().size()==0)
			result.addError("instructions",ValidationMessages.IS_MISSING);
		else
		{
			Iterator<InstructionDTO> i = data.getInstructions().iterator();
			while(i.hasNext())
			{
				InstructionDTO instr = i.next();
				check = instr.getType();
				if(check==null)
					result.addError("instruction.type",ValidationMessages.IS_MISSING);
				
				check = instr.getStatus();
				if(check==null)
					result.addError("instruction.status",ValidationMessages.IS_MISSING);
				
				check = instr.getName();
				if(check==null)
					result.addError("instruction.name",ValidationMessages.IS_MISSING);
				check = instr.getDate();
				if(check==null)
					result.addError("instruction.date",ValidationMessages.IS_MISSING);
			}
		}	
		return result;
	}
	
	private static ValidationResultHDO validateAgentFields(MimsyAgentDataDTO data)
	{
		ValidationResultHDO result = new ValidationResultHDO(data,data.getConformance());
		
		Object check = data.getPreferredName();
		
		if(check==null)
			result.addError("preferredName",ValidationMessages.IS_MISSING);
		
		if(data.getConformance()==ObjectConformanceEnum.EXTENDED_1)
		{
			check = data.getBriefBio();
		
			if(check==null)
				result.addError("briefBio",ValidationMessages.IS_MISSING);
		}
		
		if(data.isIndividual())
		{			
			check = data.getFirstName();
			if(check==null)
				result.addError("firstName",ValidationMessages.IS_MISSING);
			
			check = data.getLastName();
			if(check==null)
				result.addError("lastName",ValidationMessages.IS_MISSING);
			
			check = data.getGender();
			if(check==null)
				result.addError("gender",ValidationMessages.IS_MISSING);
			
			if(data.getConformance()==ObjectConformanceEnum.EXTENDED_1)
			{
				check=data.getTitlePrefix();
				if(check==null)
					result.addError("titlePrefix",ValidationMessages.IS_MISSING);
				
				check = data.getBirthDate();
				if(check==null)
					result.addError("birthDate",ValidationMessages.IS_MISSING);
				
				check = data.getDeathDate();
				if(check==null)
					result.addError("deathDate",ValidationMessages.IS_MISSING);
			}
			
			
		}
				
		if(data.getInstructions().size()==0)
			result.addError("instructions",ValidationMessages.IS_MISSING);
		else
		{
			Iterator<InstructionDTO> i = data.getInstructions().iterator();
			int counter=1;
			while(i.hasNext())
			{
				InstructionDTO instr = i.next();
				check = instr.getType();
				if(check==null)
					result.addError("instruction."+counter+".type",ValidationMessages.IS_MISSING);
				
				check = instr.getStatus();
				if(check==null)
					result.addError("instruction."+counter+"status",ValidationMessages.IS_MISSING);
				
				check = instr.getName();
				if(check==null)
					result.addError("instruction."+counter+"name",ValidationMessages.IS_MISSING);
				check = instr.getDate();
				if(check==null)
					result.addError("instruction."+counter+"date",ValidationMessages.IS_MISSING);
				
				
				counter++;
			}
		}
		return result;
	}
	
	private static ValidationResultHDO validateMediaFields(MimsyMediaDataDTO data)
	{
		
		ValidationResultHDO result = new ValidationResultHDO(data,data.getConformance());
		
		// no instruction checking at the mo		
			Object check = data.getRecordType();
			if(check==null)
				result.addError("recordType",ValidationMessages.IS_MISSING);
			
			check = data.getDonorLocation();
			if(check==null)
				result.addError("locator",ValidationMessages.IS_MISSING);
				
			check = data.getLargeDonorLocation();
			if(check==null && data.getRecordType()!=MediaRecordTypeEnum.DOCUMENT)
				result.addError("largerFile",ValidationMessages.IS_MISSING);
			
			if(data.getRights().size()==0)
				result.addError("rights",ValidationMessages.IS_MISSING);
			else
			{
				Iterator<RightsDTO> i = data.getRights().iterator();
				int counter=1;
				while(i.hasNext())
				{
					RightsDTO r = i.next();
					check=r.getHolder();
					if(check==null)
						result.addError("rights"+counter+".holder",ValidationMessages.IS_MISSING);
					
					check=r.getType();
					if(check==null)
						result.addError("rights"+counter+".type",ValidationMessages.IS_MISSING);	
					counter++;					
				}
			}
			
			if(data.getRecordType()!=MediaRecordTypeEnum.IMAGE)
				data.setCabinetImageNumber(null);
		
		
		return result;
	}
	
	//TODO this might be better not using http
	  public static String buildMediaLibrary(HttpClient client, MimsyMediaDataDTO data, Properties props,long last_run)
	  {
		  String i_drive_location				= props.getProperty("i_drive_location");//E:/   	 
	      String resolve_media_str				= props.getProperty("resolve_media","true");
	      boolean resolve_media					= true;
	      if(resolve_media_str.equalsIgnoreCase("false"))
	    	  resolve_media=false;
	      
	      if(resolve_media==false)
	    	  return null;
	    	  //return "Media resolution not set";
	      
		  if(i_drive_location.endsWith("/"))
			  i_drive_location=i_drive_location.substring(0,i_drive_location.length()-1);
	    			  
	      File dest_file 	= new File(data.getDonorLocation());
	      log.debug("Created dest file object "+dest_file.getAbsolutePath());
	      File dest_dir  	= new File(dest_file.getParent());
	      log.debug("Created dest dir object "+dest_dir.getAbsolutePath());
	      String retval		= null;	
	      GetMethod method	= null;
	    
	      try
	      {	 
	    	  method 				= new GetMethod(i_drive_location+data.getDonorRelativePath());
	    	  method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, 
		               		new DefaultHttpMethodRetryHandler(0, false));
			
	    	  log.debug("Build media library about to execute get method for media");
	    	  int statusCode = client.executeMethod(method);
	    	  
	    	  log.debug("Build media library  executed get method for media");       
	    	  if (statusCode != HttpStatus.SC_OK) 
	    	  {
	    		  log.debug("status code "+statusCode);
	    		  retval="Http error: "+method.getStatusLine();
	    	  }
	    	  else
	    	  {				    		 
	    		  if(dest_dir.exists()==false)
	    		  {
	    			  if(dest_dir.mkdirs()==false)
	    				  retval = "Can't create destination directory structure: "+dest_dir.getAbsolutePath();
				  } 
	    		  
	    		  byte[] file_bytes = method.getResponseBody();
	    		  method.releaseConnection();
	    		 // String last_modified = new Date();
			     //       method.getResponseHeader("last-modified").getValue();

	    		  if(dest_file.exists()) // assume if sizes same - files same yeehaa
	    		  {
	    			 
	    			  log.debug("Image updated "+dest_file.getAbsolutePath());
	    			  return null;
	    			  
	    		  }
	    		  BufferedInputStream is = new BufferedInputStream(new ByteArrayInputStream(file_bytes));
	    		  if(retval==null)
	    		  {
					  FileOutputStream fos  = new FileOutputStream(dest_file);
					              	
					  byte buf[]=new byte[1024];
					  int len;
					  while((len=is.read(buf))>0)
					  {
						  fos.write(buf,0,len);
					  }
					  fos.close();
					  is.close();	
	    		  }
	    	  }
				 
	    	  
	    	  if(retval==null && data.getLargeDonorLocation()!=null)
	    	  {  					  
	    		  // full size media
	    		  method 				= new GetMethod(i_drive_location+data.getLargeDonorRelativePath());
	    		  method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, 
			               		new DefaultHttpMethodRetryHandler(0, false));
	    		  dest_file = new File(data.getLargeDonorLocation());
	    		  dest_dir  = new File(dest_file.getParent());  
	    		  if(dest_dir.exists()==false)
	    		  {
	    			  if(dest_dir.mkdirs()==false)
	    				  retval = "Can't create destination directory structure: "+dest_dir.getAbsolutePath();				 
	    		  } 
	    		  if(retval==null)
	    		  {
		    		  statusCode = client.executeMethod(method);
		    		  byte[] bytes = null;  
		    		  if (statusCode != HttpStatus.SC_OK) 
		    		  {
		    			  retval="Http error: "+method.getStatusLine();
		    		  }
		    		  else
		    		  {			
		    			  bytes = method.getResponseBody();					
		    		  }
						  
		    		  if(bytes!=null && retval==null)
		    		  {
                                      // copy donor large file
                                      // then 3 x scaled files
                                      FileOutputStream fos = new FileOutputStream(dest_file);
                                      ByteArrayInputStream is = new ByteArrayInputStream(bytes);
                                      BufferedInputStream bis = new BufferedInputStream(is);
                                      byte buf[] = new byte[1024];
                                      int len;
                                      while ((len = is.read(buf)) > 0) {
                                          fos.write(buf, 0, len);
                                      }
                                      fos.close();
                                      bis.close();

                                      if (data.getRecordType() == MediaRecordTypeEnum.IMAGE) {
                                          System.setProperty("com.sun.media.jai.disableMediaLib", "true");
                                          is = new ByteArrayInputStream(bytes);
                                          bis = new BufferedInputStream(is);
                                          // read in the original image from an input stream
                                          SeekableStream seekableImageStream = SeekableStream.wrapInputStream(bis, true);
                                          RenderedOp originalImage = JAI.create("stream", seekableImageStream);
                                          ((OpImage) originalImage.getRendering()).setTileCache(null);


                                          double large_scale = 1.0;
                                          double mid_scale = 1.0;
                                          double small_scale = 1.0;
                                          double large_scale_height = 1.0;

                                          if (originalImage.getWidth() == 0) {
                                              return "Image with zero width";
                                          }


                                          large_scale = (double) MAX_WIDTH_LARGE / originalImage.getWidth();
                                          large_scale_height = (double) MAX_HEIGHT_LARGE / originalImage.getHeight();
                                          mid_scale = (double) MAX_WIDTH_MID / originalImage.getWidth();
                                          small_scale = (double) MAX_WIDTH_PREVIEW / originalImage.getWidth();

                                          // Ensure that we never make the image bigger than it is to start with
                                          if (large_scale > 1.0 && large_scale_height > 1.0) {
                                              retval = "Image is too small for largest size (width or height) ";
                                          } else // now create the scaled images
                                          {
                                              if (large_scale <= 1.0) {
                                                  bytes = convertImage(originalImage, large_scale);
                                              } else {
                                                  bytes = convertImage(originalImage, large_scale_height);
                                              }

                                              dest_file = new File(data.getLargeFileLocation());
                                              dest_dir = new File(dest_file.getParent());
                                              if (dest_dir.exists() == false) {
                                                  if (dest_dir.mkdirs() == false) {
                                                      throw new Exception("Can't create destination directory structure: " + dest_dir.getAbsolutePath());
                                                  }
                                              }

                                              FileOutputStream convertedFos = new FileOutputStream(dest_file);
                                              ByteArrayInputStream convertedIs = new ByteArrayInputStream(bytes);
                                              BufferedInputStream convertedBis = new BufferedInputStream(convertedIs);
                                              buf = new byte[1024];

                                              while ((len = convertedIs.read(buf)) > 0) {
                                                  convertedFos.write(buf, 0, len);
                                              }
                                              convertedFos.close();
                                              convertedBis.close();

                                              bytes = convertImage(originalImage, mid_scale);
                                              dest_file = new File(data.getMidFileLocation());
                                              dest_dir = new File(dest_file.getParent());
                                              if (dest_dir.exists() == false) {
                                                  if (dest_dir.mkdirs() == false) {
                                                      throw new Exception("Can't create destination directory structure: " + dest_dir.getAbsolutePath());
                                                  }
                                              }
                                              convertedFos = new FileOutputStream(dest_file);
                                              convertedIs = new ByteArrayInputStream(bytes);
                                              convertedBis = new BufferedInputStream(convertedIs);
                                              buf = new byte[1024];

                                              while ((len = convertedIs.read(buf)) > 0) {
                                                  convertedFos.write(buf, 0, len);
                                              }
                                              convertedFos.close();
                                              convertedBis.close();

                                              bytes = convertImage(originalImage, small_scale);
                                              dest_file = new File(data.getPreviewFileLocation());
                                              dest_dir = new File(dest_file.getParent());
                                              if (dest_dir.exists() == false) {
                                                  if (dest_dir.mkdirs() == false) {
                                                      throw new Exception("Can't create destination directory structure: " + dest_dir.getAbsolutePath());
                                                  }
                                              }
                                              convertedFos = new FileOutputStream(dest_file);
                                              convertedIs = new ByteArrayInputStream(bytes);
                                              convertedBis = new BufferedInputStream(convertedIs);
                                              buf = new byte[1024];

                                              while ((len = convertedIs.read(buf)) > 0) {
                                                  convertedFos.write(buf, 0, len);
                                              }
                                              convertedFos.close();
                                              convertedBis.close();

                                          }

                                          // Now we're finished close the remaining streams
                                          bis.close();
                                          fos.close();
                                      }

					}	
	    		  }
				 }  
		      }
		      catch (HttpException e) 
		      {
		    	  	log.debug(e);
		      		retval="Http protocol error: "+e.getMessage();
		            //log.error("Fatal protocol violation: " + e);
		      } 
		      catch (IOException e) 
		      {
		    	  	log.debug(e);
		      		retval="Transport error: "+e.getMessage();
		      		//log.error("Fatal transport error: " + e);
		      }
                      catch(Exception e)
                      {
	        	  log.debug("Exception thrown : " + e.getMessage());
	        	  retval="Error: "+e.getMessage();
	            	//log.error("Exception: " + e);
                      }
                      catch(Throwable t)
                      {
                            log.debug("Throwable caught: " + t.getMessage());
                            t.printStackTrace();
                            retval = "Throwable thrown: " + t.getMessage();
                      }
		      finally 
		      {
		                // Release the connection.
		        if(method!=null)
		                method.releaseConnection();		               
		      }		      
	      return retval;
	  }
	 
	  private static byte[] convertImage(RenderedOp originalImage, double scale) {

			RenderingHints qualityHints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
	    	RenderedOp resizedImage = null;
		    byte[] resizedImageByteArray = null;


	    	ParameterBlock paramBlock = new ParameterBlock();
	    	paramBlock.addSource(originalImage); // The source image
	    	paramBlock.add(scale); // The xScale
	    	paramBlock.add(scale); // The yScale
	    	paramBlock.add(0.0); // The x translation
	    	paramBlock.add(0.0); // The y translation
	    	resizedImage = JAI.create("SubsampleAverage", paramBlock, qualityHints);

	    	// Perform the actual conversion to PNG
	    	ByteArrayOutputStream encoderOutputStream = new ByteArrayOutputStream();
	    	JAI.create("encode", resizedImage, encoderOutputStream, "JPEG", null);
	    	// Export to Byte Array
	    	resizedImageByteArray = encoderOutputStream.toByteArray();
			
	    	return resizedImageByteArray;
		}
		
	
	private static ValidationResultHDO validatePlaceFields(MimsyPlaceDataDTO data)
	{
		ValidationResultHDO result = new ValidationResultHDO(data,data.getConformance());
		
		Object check = data.getPlace();
		if(check==null)
			result.addError("placeName",ValidationMessages.IS_MISSING);
								
		check = data.getLevelNumber();
		if(check==null)
			result.addError("levelNumber",ValidationMessages.IS_MISSING);
		
		check = data.getBroaderPlace();
		if(check==null)
			result.addError("broaderPlace",ValidationMessages.IS_MISSING);
		
		if(data.getConformance()==ObjectConformanceEnum.EXTENDED_1)
		{
			check = data.getDescription();
			if(check==null)
				result.addError("description",ValidationMessages.IS_MISSING);
		}
		
		if(data.getInstructions().size()==0)
			result.addError("instructions",ValidationMessages.IS_MISSING);
		else
		{
			Iterator<InstructionDTO> i = data.getInstructions().iterator();
			while(i.hasNext())
			{
				InstructionDTO instr = i.next();
				check = instr.getType();
				if(check==null)
					result.addError("instruction.type",ValidationMessages.IS_MISSING);
				
				check = instr.getStatus();
				if(check==null)
					result.addError("instruction.status",ValidationMessages.IS_MISSING);
				
				check = instr.getName();
				if(check==null)
					result.addError("instruction.name",ValidationMessages.IS_MISSING);
				check = instr.getDate();
				if(check==null)
					result.addError("instruction.date",ValidationMessages.IS_MISSING);
			}
		}
		//if(result.getStatus()==ValidationResult.STATUS_INVALID)
		//	log.debug("Validation result "+result);	
		return result;
	}
	
	// no info from MoL yet
	private static ValidationResultHDO validateSubjectFields(MimsySubjectDataDTO data)
	{
		ValidationResultHDO result = new ValidationResultHDO(data,ObjectConformanceEnum.EXTENDED_2);
		return result;
	}
	
	// no info from MoL yet
	private static ValidationResultHDO validatePublicationFields(MimsyPublicationDataDTO data)
	{
		ValidationResultHDO result = new ValidationResultHDO(data,ObjectConformanceEnum.EXTENDED_2);
		return result;
	}

}
