package gov.va.vinci.dart.dms.db.mock;

import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;

import javax.persistence.Query;

import gov.va.vinci.dart.common.exception.ObjectNotFoundException;
import gov.va.vinci.dart.biz.DartRequest;
import gov.va.vinci.dart.biz.OperationalRequest;
import gov.va.vinci.dart.biz.Participant;
import gov.va.vinci.dart.biz.Request;
import gov.va.vinci.dart.biz.RequestAdminLocationDocument;
import gov.va.vinci.dart.biz.Location;
import gov.va.vinci.dart.biz.RequestAdminParticipantDocument;
import gov.va.vinci.dart.biz.RequestLocationDocument;
import gov.va.vinci.dart.biz.RequestParticipantDocument;
import gov.va.vinci.dart.db.LocationDAO;
import gov.va.vinci.dart.db.ParticipantDAO;
import gov.va.vinci.dart.db.RequestAdminLocationDocumentDAO;
import gov.va.vinci.dart.db.RequestAdminParticipantDocumentDAO;
import gov.va.vinci.dart.db.RequestLocationDocumentDAO;
import gov.va.vinci.dart.db.RequestParticipantDocumentDAO;
import gov.va.vinci.dart.dms.biz.Content;
import gov.va.vinci.dart.dms.biz.Document;
import gov.va.vinci.dart.dms.biz.Label;
import gov.va.vinci.dart.dms.biz.Repository;
import gov.va.vinci.dart.dms.db.DocumentDAO;
import gov.va.vinci.dart.dms.db.LabelDAO;
import gov.va.vinci.dart.service.DartObjectFactory;

public class DocumentDAOMock implements DocumentDAO {
	private static HashMap<Integer,Document> IDHash = new HashMap<Integer,Document>();
	private static boolean initialized = false;
	private static int idCounter = 1;

	@Override
	public synchronized void save(Document document) {
		if (document == null) {
			throw new IllegalArgumentException();
		}
		
		initializeDocumentHash();
		
		if (document.getId() == 0) {
			document.setId(idCounter++);
		}
		
		// Hibernate does this automatically
		if (document.getRequest() != null && document.getRequest().getDocuments() != null && document.getRequest().getDocuments().contains(document) == false) {
			document.getRequest().getDocuments().add(document);
		}

		IDHash.put(document.getId(), document);
	}

	@Override
	public void delete(Document document) {
		if (document == null) {
			throw new IllegalArgumentException();
		}

		initializeDocumentHash();

		// Hibernate does this automatically
		for (DartRequest req : DartObjectFactory.getInstance().getDartRequestDAO().listAll()) {
			if (req.getDocuments() != null && req.getDocuments().contains(document)) {
				req.getDocuments().remove(document);
			}
		}

		// Hibernate does this automatically
		for (OperationalRequest req : DartObjectFactory.getInstance().getOperationalRequestDAO().listAll()) {
			if (req.getDocuments() != null && req.getDocuments().contains(document)) {
				req.getDocuments().remove(document);
			}
		}

		IDHash.remove(document.getId());
	}

	@Override
	public Document findById(int documentId) {
		initializeDocumentHash();
		
		return IDHash.get(documentId);
	}

	@Override
	public List<Document> listVersionsByReqIdandTemplIdandContId(int requestId, int templateId, int contentId) {
		List<Document> result = new ArrayList<Document>();
		
		initializeDocumentHash();
		
		for (Integer id: IDHash.keySet()) {
			Document doc = IDHash.get(id);
			if (doc.getRequest().getId() == requestId && doc.getDocumentTemplate().getId() == templateId && doc.getContent().getId() == contentId) {
				result.add(doc);
			}
		}
		return result;	
	}	
	
	@Override
	public List<Document> listVersionsByReqIdandTemplId(int requestId, int templateId) {
		List<Document> result = new ArrayList<Document>();
		
		initializeDocumentHash();
		
		for (Integer id: IDHash.keySet()) {
			Document doc = IDHash.get(id);
			if (doc.getRequest().getId() == requestId && doc.getDocumentTemplate().getId() == templateId) {
				result.add(doc);
			}
		}
		return result;	
	}	
	
	@Override
	public List<Document> listVersionsById(int documentId) {
		List<Document> result = new ArrayList<Document>();
		
		initializeDocumentHash();
		
		for (Integer id: IDHash.keySet()) {
			Document doc = IDHash.get(id);
			if (doc.getHead() == documentId || doc.getId() == documentId) {
				result.add(doc);
			}
		}

		return result;	
	}		
	
	
//	@Override
	public List<Document> listVersionsByReqIdSortId(int requestId, int sortorderId) {
		List<Document> result = new ArrayList<Document>();
		
		initializeDocumentHash();
		
		for (Integer id: IDHash.keySet()) {
			Document doc = IDHash.get(id);
			Request req = doc.getRequest();
			if (req.getId() == requestId && doc.getSortOrder() == sortorderId) {
				result.add(doc);
			}
		}
		return result;	
	}	

	@Override
	public List<Document> listAll() {
		List<Document> result = new ArrayList<Document>();
		
		initializeDocumentHash();
		
		for (Integer id: IDHash.keySet()) {
			Document doc = IDHash.get(id);
			result.add(doc);
		}

		return result;	
	}

	@Override
	public List<Document> listByContentId(int contentId) {
		List<Document> result = new ArrayList<Document>();

		initializeDocumentHash();
		
		for (Integer id: IDHash.keySet()) {
			Document doc = IDHash.get(id);
			Content cont = doc.getContent();
			if (cont != null && cont.getId() == contentId) {
				result.add(doc);
			}
		}
		
		return result;
	}

	@Override
	public List<Document> listByRepositoryId(final int repositoryId) {
		List<Document> result = new ArrayList<Document>();

		initializeDocumentHash();
		
		for (Integer id: IDHash.keySet()) {
			Document doc = IDHash.get(id);

			Content cont = doc.getContent();
			if (cont != null) {
				
				Repository repo = cont.getRepository();
				if( repo != null && repo.getId() == repositoryId ) {
					result.add(doc);
				}
				
			}
		}
		
		return result;
	}
	
	@Override
	public List<Document> listByRequestAndNonNullContentId(final int requestId, final int contentId) {
		List<Document> result = new ArrayList<Document>();

		initializeDocumentHash();
		
		for (Integer id: IDHash.keySet()) {
			Document doc = IDHash.get(id);
			Content cont = doc.getContent();
			if( (doc.getRequest() != null && doc.getRequest().getId() == requestId) &&
				(cont != null && cont.getId() == contentId) ) {
				
				result.add(doc);
				
			}
		}
		
		return result;
	}
	
	
	@Override
	public Document findCurrentVersion(int documentId) {
		initializeDocumentHash();
		
		LabelDAO mock = DartObjectFactory.getInstance().getLabelDAO();
		
		// first find the head of the document version chain
		Document document = IDHash.get(documentId);

		Document head = IDHash.get(document.getHead()); 
		
		if (head == null) {
			return null;
		}
		
		// now check every document that lists that head as it's head
		for (Integer id: IDHash.keySet()) {
			Document doc = IDHash.get(id);
			
			if (doc.getHead() == head.getId()) {

				// is this document related to the one listed?
				for (Label lbl : mock.listByDocumentId(id)) {
					if (Document.CURRENT_LABEL.equals(lbl.getValue())) {
						return doc;
					}
				}
			}
		}
		
		return null;
	}

	@Override
	public Document findMostRecentVersion(int documentId) {
		initializeDocumentHash();

		GregorianCalendar gc = new GregorianCalendar();
		gc.set(1900, 0, 1);
		Date max = gc.getTime();
		Document current = null;
		
		List<Document> dlist = listVersionsById(documentId);
		
		for (Document doc: dlist) {
			Date d = doc.getUpdatedOn();
			if (d == null) {
				d = doc.getCreatedOn();
			}
			
			if (d.after(max)) {
				max = d;
				current = doc;
			}
		}

		return current;
	}	
	
	@Override
	public Document findMostRecentSortorder(final int requestId, final int sortorderId, final int contentId) {
		initializeDocumentHash();

		GregorianCalendar gc = new GregorianCalendar();
		gc.set(1900, 0, 1);
		Date max = gc.getTime();
		Document current = null;
		
		List<Document> dlist = listVersionsByReqIdSortId(requestId, sortorderId);
		
		for (Document doc: dlist) {
			Date d = doc.getUpdatedOn();
			if (d == null) {
				d = doc.getCreatedOn();
			}
			
			if (d.after(max)) {
				max = d;
				current = doc;
			}
		}

		return current;
	}	

	@Override
	public String findLocationByDocId(int documentId) {
		initializeDocumentHash();

		LocationDAO locationMock = DartObjectFactory.getInstance().getLocationDAO();
		ParticipantDAO participantMock = DartObjectFactory.getInstance().getParticipantDAO();
		RequestAdminLocationDocumentDAO raldMock = DartObjectFactory.getInstance().getRequestAdminLocationDocumentDAO();
		RequestAdminParticipantDocumentDAO rapdMock = DartObjectFactory.getInstance().getRequestAdminParticipantDocumentDAO();
		RequestLocationDocumentDAO rldMock = DartObjectFactory.getInstance().getRequestLocationDocumentDAO();
		RequestParticipantDocumentDAO rpdMock = DartObjectFactory.getInstance().getRequestParticipantDocumentDAO();

		Location loc = null;
		Participant part = null;
		
		List<RequestAdminLocationDocument> raldList = raldMock.listByDocumentId(documentId);
		if (raldList != null && raldList.size() > 0) {
			try {
				loc = locationMock.findById(raldList.get(0).getLocationId());
				return loc.getName();
			}
			catch (ObjectNotFoundException e) {
			}
		}

		List<RequestAdminParticipantDocument> rapdList = rapdMock.listByDocumentId(documentId);
		if (rapdList != null && rapdList.size() > 0) {
			part = participantMock.findById(rapdList.get(0).getParticipantId());
			return part.getLocation().getName();
		}

		List<RequestLocationDocument> rldList = rldMock.listByDocumentId(documentId);
		if (rldList != null && rldList.size() > 0) {
			try {
				loc = locationMock.findById(rldList.get(0).getLocationId());
				return loc.getName();
			}
			catch (ObjectNotFoundException e) {
			}
		}

		List<RequestParticipantDocument> rpdList = rpdMock.listByDocumentId(documentId);
		if (rpdList != null && rpdList.size() > 0) {
			part = participantMock.findById(rpdList.get(0).getParticipantId());
			return part.getLocation().getName();
		}

		return null;
	}

	@Override
	public String findParticipantNameByDocId(int documentId) {
		initializeDocumentHash();
		
		ParticipantDAO participantMock = DartObjectFactory.getInstance().getParticipantDAO();
		RequestAdminParticipantDocumentDAO rapdMock = DartObjectFactory.getInstance().getRequestAdminParticipantDocumentDAO();
		RequestParticipantDocumentDAO rpdMock = DartObjectFactory.getInstance().getRequestParticipantDocumentDAO();
		
		Participant part = null;
		
		List<RequestAdminParticipantDocument> rapdList = rapdMock.listByDocumentId(documentId);
		if (rapdList != null && rapdList.size() > 0) {
			part = participantMock.findById(rapdList.get(0).getParticipantId());
			return part.getPerson().getFullName();
		}

		List<RequestParticipantDocument> rpdList = rpdMock.listByDocumentId(documentId);
		if (rpdList != null && rpdList.size() > 0) {
			part = participantMock.findById(rpdList.get(0).getParticipantId());
			return part.getPerson().getFullName();
		}

		return null;
	}

	private void initializeDocumentHash() {
		if (initialized == true) {
			return;
		}
		
		initialized = true;
	}
	
    @Override
    public int countRequestAndNonNullContentId(final int requestId,final int contentId) {
        //Query q = createQuery("SELECT count(*) FROM Document doc where doc.request.id=:rid and (content is not null and content.id=:cid");
		//q.setParameter("cid", contentId);
		//q.setParameter("rid", requestId);
        Long lVal = (Long) 1L;

        return (int) lVal.longValue();
    }
}

///*
// * 	
//	// check the RequestAdminLocationDocument, RequestAdminParticipantDocument, RequestLocationDocument, RequestParticipantDocument
//	// in that order for a location name associated with the document
//	@Override
//	public String findLocationByDocId(final int documentId) {
//		Query q = createNativeQuery("select case when rald.DocumentID is not null then admLoc.Name "+
//				" when rapd.documentID is not null then AdmPartloc.Name "+
//				" when rld.DocumentID is not null then l.Name "+
//				" when rpd.DocumentID is not null then l2.Name "+
//				" else null end as DocumentLocation"+
//				" from hib.Document doc "+
//				" left join [hib].[requestadminlocationdocument] rald on doc.ID = rald.DocumentID "+
//				" left join hib.Location AdmLoc on rald.locationid = AdmLoc.ID "+
//				" left join [hib].[requestadminparticipantdocument] rapd on doc.ID = rapd.documentid "+
//				" left join hib.participant admPart on rapd.participantid  = admPart.ID "+
//				" left join hib.Location AdmPartloc on admPart.LocationID = AdmPartLoc.ID "+
//				" left join  [hib].[requestlocationdocument] rld on doc.ID = rld.documentid "+
//				" left join hib.Location l on rld.LocationID = l.ID "+
//				" left join [hib].[requestparticipantdocument] rpd on doc.ID = rpd.documentid "+
//				" left join hib.Participant p on rpd.ParticipantID = p.ID "+
//				" left join hib.Location l2 on p.locationid = l2.id "+
//				" where doc.ID =:docid");
//		q.setParameter("docid", documentId);
//		try {
//			return (String)q.getSingleResult();
//		} catch (NoResultException e) {
//			return null;
//		}
//	}
//	
//	// check the RequestAdminParticipantDocument, and RequestParticipantDocument in that order for the name of the participant associated with a document
//	@Override
//	public String findParticipantNameByDocId(final int documentId) {
//		Query q = createNativeQuery("select case when rapd.documentID is not null then pers1.FullName "+
//				" when rpd.DocumentID is not null then pers2.Fullname end as PersonFullName "+
//				" from hib.Document doc "+
//				" left join [hib].[requestadminlocationdocument] rald on doc.ID = rald.DocumentID "+
//				" left join hib.Location AdmLoc on rald.locationid = AdmLoc.ID "+
//				" left join [hib].[requestadminparticipantdocument] rapd on doc.ID = rapd.documentid "+
//				" left join hib.participant admPart on rapd.participantid = admPart.ID "+
//				" left join hib.Location AdmPartloc on admPart.LocationID = AdmPartLoc.ID "+
//				" left join hib.Person pers1 on admpart.PersonID = pers1.ID "+
//				" left join  [hib].[requestlocationdocument] rld on doc.ID = rld.documentid "+
//				" left join hib.Location l on rld.LocationID = l.ID "+
//				" left join [hib].[requestparticipantdocument] rpd on doc.ID = rpd.documentid "+
//				" left join hib.Participant p on rpd.ParticipantID = p.ID "+
//				" left join hib.Location l2 on p.locationid = l2.id "+
//				" left join hib.Person pers2 on p.PersonID = pers2.ID "+
//				" where doc.ID=:docid");
//		q.setParameter("docid", documentId);
//		try {
//			return (String)q.getSingleResult();
//		} catch (NoResultException e) {
//			return null;
//		}
//	}


