package com.libreecm.input.repositoriesImpl;

import com.libreecm.commonAPI.model.Repository;
import com.libreecm.commonAPI.model.enums.BaseTypeId;
import com.libreecm.commonAPI.model.objects.*;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import com.libreecm.commonAPI.auxiliars.exceptions.*;
/**
 * This class defines a Repository and all it's attributes
* Id: is an INTEGER that refers the object persistence, if not persisted "0"
* Path: is a URI: Type://Name/baseFolder/secondFolder/.../parentFolder/repositoryRoot/
* 		- Type defines the repository Type
* 		- Name defines so it could difference between same type repositories
* 		- Folders tree
* 		- Object is always ""
* As it represents a persisted system in a FS or a DB, the information
* defined in this class is obtained from that sources
*/ 
public abstract class RepositoryImpl extends Repository {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * To not be used. A repository needs at least some information to be created:
	 * Name and Path are mandatory
	 */
	private RepositoryImpl(){
		super();
	}
	
	public RepositoryImpl(Repository rep){
		super();
		this.setDefaultCapabilities();
		if (rep.getTypeId()==null){
			throw new NotDefinedRepositoryTypeException();
		}
		this.setAccessible(rep.isAccessible());
		this.setAclCapabilities(rep.getAclCapabilities());
		this.setActive(rep.isActive());
		this.setChangesIncomplete(rep.getChangesIncomplete());
		this.setChangesOnType(rep.getChangesOnType());
		this.setCmisExtensionElements(rep.getCmisExtensionElements());
		this.setCmisVersion(rep.getCmisVersion());
		this.setCmisVersionSupported(rep.getCmisVersionSupported());
		this.setCustomizedTypes(rep.getCustomizedTypes());
		this.setDescription(rep.getDescription());
		this.setExtensionFeatures(rep.getExtensionFeatures());
		this.setId(rep.getId());
		this.setLatestChangeLogToken(rep.getLatestChangeLogToken());
		this.setName(rep.getName());
		this.setPath(rep.getPath());
		this.setPrincipalIdAnonymous(rep.getPrincipalIdAnonymous());
		this.setPrincipalIdAnyone(rep.getPrincipalIdAnyone());
		this.setProductName(rep.getProductName());
		this.setProductVersion(rep.getProductVersion());
		this.setRepositoryCapabilities(rep.getRepositoryCapabilities());
		this.setRootFolderId(rep.getRootFolderId());
		this.setThinClientUri(rep.getThinClientUri());
		this.setTypeId(rep.getTypeId());
		this.setVendorName(rep.getVendorName());
		this.setAllowedObjectTypes();
	}
	
	/**
	 * Creates a new Repository pointing to a file system path Uri should have
	 * to be formatted:
	 * "FSRepository://repositoryId/rootFolder/secondRootFolder/.../parentFolder/baseFolder/"
	 * Object pointed from Uri should be null or empty It could have any folder
	 * tree size.
	 * 
	 * @param url
	 */
	public RepositoryImpl(Uri uri){
		super();
		this.setDefaultCapabilities();
		if (uri==null)
			throw new NotDefinedRepositoryUriException();
		this.setName(uri.getRepositoryName());
		this.setPath(uri.toString());
		this.setTypeId(uri.getType());
		if (uri.getType()==null){
			throw new NotDefinedRepositoryTypeException();
		}
		Uri rootFolderUri= new Uri();
		rootFolderUri.setObject("");
		rootFolderUri.setRepositoryName(this.getName());
		rootFolderUri.setType(BaseTypeId.CMIS_FOLDER.value());
		rootFolderUri.setFolderTree(new ArrayList<String>());
		this.setRootFolderId(rootFolderUri.toString());
		this.setAllowedObjectTypes();
	}

	public abstract AllowableActions getAllowedActions();
	

	/**
	 * @return the allowedObjectTypeId
	 */
	public List<ObjectType> getAllowedObjectTypeId() {
		if (super.getAllowedObjectTypeId()==null)
			setAllowedObjectTypeId(new ArrayList<>());
		return super.getAllowedObjectTypeId();
	}

	public abstract List<LibreECMDataObject> getChildren(String folderId);

	public abstract LibreECMDataObject getCustomized(Uri uri, String type);
	
	public  abstract Document getDocument(Uri uri);
	
	public abstract  Folder getFolder(Uri uri) ;
	

	public  abstract Item getItem(Uri uri);
	/**
	 * Returns a object 
	 * @param path
	 * @return Object read
	 */
	public LibreECMDataObject getObject(Uri uri) {
		LibreECMDataObject result = null;
		if (uri.getType().equals(BaseTypeId.CMIS_ITEM.value()))
			result = getItem(uri);
		else if (uri.getType().equals(BaseTypeId.CMIS_DOCUMENT.value()))
			result = getDocument(uri);
		else if (uri.getType().equals(BaseTypeId.CMIS_FOLDER.value()))
			result = getFolder(uri);
		else if (uri.getType().equals(BaseTypeId.CMIS_RELATIONSHIP.value()))
			result = getRelationship(uri);
		else if (uri.getType().equals(BaseTypeId.CMIS_POLICY.value()))
			result = getPolicy(uri);
		else {
			boolean found = false;
			for (String type : this.getCustomizedTypes()) {
				if (type.equals(uri.getType())) {
					result = getCustomized(uri, type);
					found = true;
				}
			}
			if (!found)
				throw new NotDefinedBaseTypeIdException(uri.getObject(), uri.getType());
		}

		return result;
	}
	public abstract InputStream getObjectStream(String path);
	/**
	 * Creates the base of an object at this repository
	 * @param cmisObjectTypeId (as Id)
	 * @return
	 */
	public ObjectType getObjectType(String objectTypeId){
		for (ObjectType element: getAllowedObjectTypeId()) {
			if (element.getId().equals(objectTypeId)){
				return element;
			}
		}
		throw new NotAllowedObjectTypeException(objectTypeId);
	}
	public  abstract Policy getPolicy(Uri uri);
	public  abstract Relationship getRelationship(Uri uri) ;
	
	public abstract Uri getUri();
	
	/**
	 * Sets witch basetypes could a repository maintain
	 * @param list
	 */
	protected abstract void setAllowedObjectTypes();
	protected abstract void setDefaultCapabilities();
	public abstract void setDocument(Document element, Uri newPath);
	public abstract  void setFolder(Folder element, Uri newPath) ;
	/**
	 * Creates a Item in the repository. 
	 * Remember, Item is an always empty document
	 * @param element
	 */
	public abstract void setItem(Item element, Uri newPath);

	public void setObject(LibreECMDataObject element,Uri newPath) {
		
		if (element.getBaseTypeId().equals(BaseTypeId.CMIS_DOCUMENT.value())) setDocument((Document)element, newPath);
		else if (element.getBaseTypeId().value().equals(BaseTypeId.CMIS_ITEM.value())) setItem((Item)element, newPath);
		else if (element.getBaseTypeId().value().equals(BaseTypeId.CMIS_POLICY.value())) setPolicy((Policy)element);
		else if (element.getBaseTypeId().value().equals(BaseTypeId.CMIS_FOLDER.value())) setFolder((Folder)element, newPath);
		else if (element.getBaseTypeId().value().equals(BaseTypeId.CMIS_RELATIONSHIP.value())) setRelationship((Relationship)element);
		else throw new NotDefinedBaseTypeIdException(element.getId(), element.getBaseTypeId().value());
	}
	/**
	 * Sets a new Object
	 * @return String with the new Id
	 */


	public abstract void setObjectStream(Uri uri, InputStream stream);
	
	public abstract void setPolicy(Policy element);

	public abstract void setRelationship(Relationship element) ;
	

}
