package org.gcube.contentmanager.storageserver.accounting;

import java.net.URI;
import java.net.URISyntaxException;
import org.gcube.accounting.datamodel.UsageRecord.OperationResult;
import org.gcube.accounting.datamodel.basetypes.AbstractStorageUsageRecord.OperationType;
import org.gcube.accounting.datamodel.usagerecords.StorageUsageRecord;
import org.gcube.documentstore.exception.InvalidValueException;
import org.gcube.accounting.persistence.AccountingPersistence;
import org.gcube.accounting.persistence.AccountingPersistenceFactory;
import org.gcube.contentmanager.storageserver.parse.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

	public class ReportAccountingImpl implements Report {
	private static final String DEFAULT_PRODUCTION_ROOT_SCOPE = "d4science.research-infrastructures.eu";
	private static final String DEFAULT_PRODUCTION_PROVIDER_URI = "data.d4science.org";
	final Logger logger = LoggerFactory.getLogger(ReportAccountingImpl.class);
//	public StorageUsageRecord sur;
	public AccountingPersistence accountingPersistence;
	private String providerUri;
//	public ResourceAccounting raFactory;

	
	@Override
	public void init(){
		accountingPersistence = AccountingPersistenceFactory.getPersistence();
		  try {
//			  sur = new StorageUsageRecord();
		  }
		  catch (Exception e) {
			  e.printStackTrace();
		  }  
	}
	
	@Override
	public StorageUsageRecord setGenericProperties(StorageUsageRecord sur, String resourceType, String consumerId, String resourceScope, String creationTime, String lastAccess, String owner, String operation, String size) {
		  logger.trace("set accounting generic properties:  operation: "+operation+" resourceType: "+resourceType+" consumerId "+consumerId+" scope: "+resourceScope+ " creationTime "+creationTime+" lastAccess "+lastAccess+" owner "+ owner);
		  if(accountingPersistence==null) init();
		  if (sur == null)
			  sur = new StorageUsageRecord();
//		  logger.debug("id generated by backend "+sur.getId());
			try {
 				 sur.setDataType(StorageUsageRecord.DataType.STORAGE);
				 sur.setOperationResult(OperationResult.SUCCESS);
				 if(consumerId!=null) sur.setConsumerId(consumerId);
				 if(resourceScope !=null){
					 sur.setResourceScope(resourceScope);
		//it is extracted from resourceScope			 
					 sur=setProviderUri(sur, resourceScope);
				 }
				 if(owner != null) sur.setResourceOwner(owner);
				 if (operation != null){
					 OperationType accountingOperation=convertOperation(operation);
					 logger.debug("operation converted: "+accountingOperation);
					 sur.setOperationType(accountingOperation);
				 }
				 if(size!= null) sur.setDataVolume(Long.parseLong(size));
				 
			} catch (org.gcube.documentstore.exception.InvalidValueException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			} catch (URISyntaxException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		   logger.trace("generic fields completed ");
		   return sur;
	}

	protected StorageUsageRecord setProviderUri(StorageUsageRecord sur, String resourceScope) throws InvalidValueException, URISyntaxException {
		logger.trace("retrieve root scope from  resourceScope "+resourceScope);
		 String rootScope= resourceScope.substring(1);
		 logger.trace("rootScope extrapolated is: "+rootScope);
		 if(sur == null)
			 sur=new StorageUsageRecord();
		 sur.setProviderURI(new URI(buildProviderURI(resourceScope)));
		 return sur;
	}

	protected String buildProviderURI(String resourceScope){
		String rootScope= resourceScope.substring(1);
		if(resourceScope.contains(DEFAULT_PRODUCTION_ROOT_SCOPE)){
			 providerUri=DEFAULT_PRODUCTION_PROVIDER_URI;
			 return providerUri;
		 }
		 if(rootScope.indexOf("/") != -1){
			 int i=rootScope.indexOf("/");
			 rootScope=rootScope.substring(0, i);
			 logger.trace("removed sub scopes. rootScope: "+rootScope);
		}
		 providerUri="data."+rootScope+".org";
		 logger.debug("set provider uri: "+providerUri);
		 return providerUri;
	}

	
	
	@Override
	public StorageUsageRecord setSpecificProperties(StorageUsageRecord sur, String filePath,
			String dataType, String callerIP, String id) {
	   logger.trace("set accounting properties:  remotePath: "+filePath+" dataType "+dataType+" callerIP "+callerIP+" resourceURI "+id);
	   if(sur==null) sur = new StorageUsageRecord();
		try {
			if(filePath != null){
				sur.setResourceProperty("remotePath", filePath);
			}
			if(callerIP != null){
				sur.setResourceProperty("callerIP", callerIP);
			}
			if(id != null){
				try {
					sur.setResourceURI(new URI(id));
				} catch (URISyntaxException e) {
					e.printStackTrace();
				}
			}
		} catch (InvalidValueException e) {
			e.printStackTrace();
		}
	   return sur;
	}
	
	private StorageUsageRecord.OperationType convertOperation(String operation) {
		logger.debug("converting operation: "+operation);
		switch (operation)
        {
            case "UPLOAD":
            	return StorageUsageRecord.OperationType.CREATE;
            case "DELETE":
            	return StorageUsageRecord.OperationType.DELETE;
            case "MOVE":
            	return StorageUsageRecord.OperationType.UPDATE;
            case "COPY":
            	return StorageUsageRecord.OperationType.CREATE;
            case "SOFT_COPY":
            	return StorageUsageRecord.OperationType.CREATE;
            case "MOVE_DIR":
            	return StorageUsageRecord.OperationType.UPDATE;
            case "COPY_DIR":
            	return StorageUsageRecord.OperationType.CREATE;
            case "DOWNLOAD":
            	return StorageUsageRecord.OperationType.READ;
        }
		throw new RuntimeException("The operation "+operation+" is not converted or supported");
	}

	public void printRecord(StorageUsageRecord record){
		logger.info(" Record properties: " +
				"\n\t owner: "+record.getResourceOwner()+
				"\n\t scope "+record.getResourceScope()+
				"\n\t type "+record.getOperationType()+ //ResourceType()+
				"\n\t consumer  "+record.getConsumerId()+
				"\n\t file  "+record.getResourceProperty("remotePath")+
				"\n\t size  "+record.getDataVolume()+ //("dataVolume")+
				"\n\t caller  "+record.getResourceProperty("callerIP")+
				"\n\t id  "+record.getId()+
				"\n\t resourceURI  "+record.getResourceURI()+
				"\n\t providerURI  "+record.getProviderURI()+
				"\n\t Now  "+DateUtils.now("dd MM yyyy 'at' hh:mm:ss z")+
				"\n\t operation "+record.getOperationType());//("operationType"));
	}

	@Override
	public void send(StorageUsageRecord sur) {
		accountingPersistence = AccountingPersistenceFactory.getPersistence();
		if(accountingPersistence !=null){
			logger.debug("report sending...");
			try {
				accountingPersistence.account(sur);
			} catch (InvalidValueException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			logger.info(" report send:  \n\t"+sur);
		}else
			logger.error("Problem on building accounting record: Accounting Object is null ");
	}

	public String getProviderUri() {
		return providerUri;
	}

	

}
