 /*
  * ====================================================================
  *
  * Copyright 2004 The Apache Software Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
  */
package org.apache.slide.event;

import java.io.IOException;

import org.apache.slide.common.Domain;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.SlideToken;
import org.apache.slide.common.SlideTokenWrapper;
import org.apache.slide.content.Content;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.content.RevisionDescriptorNotFoundException;
import org.apache.slide.content.RevisionNotFoundException;
import org.apache.slide.lock.ObjectLockedException;
import org.apache.slide.security.AccessDeniedException;
import org.apache.slide.structure.LinkedObjectNotFoundException;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.util.logger.Logger;
import org.apache.slide.webdav.method.AbstractWebdavMethod;


/**
 * @author Thomas Bellembois
 * 
 * Class used to manage quota automatically on a resource to be put, copied... :
 * - get the resource content length either in the request (ex : put method) or in the NRD (ex : copy method)
 * - check if the action to be done does not lead to an overquota (for every resource up to the root node or virtual root)
 *   > for put requests and if the HTTP header content length is equal to -1 then we do not check (soft quota management)
 * - update quota properties when the action is done (for every resource up to the root node or virtual root)
 */
public class QuotaElement {

	// logger
	private static final String LOG_CHANNEL = "org.apache.slide.event.QuotaElement";
	
	// SlideToken and Content get from the AbstractWebdavMethod
	private SlideToken slideToken;
	private Content content;
	
	// QuotaElement uri and contentLength (contentLength not necessary known)
	private String uri;	
	private String contentLength;
	private boolean isCollection;
	
	// Does this QuotaElement has quota MD ? Is the quota exceeded ? 
	private boolean quotaExceeded;
	private boolean hasQuota;
	
	
	/**
	 * Return true if the resource is a collection
	 * @return
	 * @throws ObjectNotFoundException
	 * @throws AccessDeniedException
	 * @throws LinkedObjectNotFoundException
	 * @throws ObjectLockedException
	 * @throws ServiceAccessException
	 * @throws VetoException
	 * @throws RevisionDescriptorNotFoundException
	 */
	public boolean isCollection() throws ObjectNotFoundException, AccessDeniedException, LinkedObjectNotFoundException, ObjectLockedException, ServiceAccessException, VetoException, RevisionDescriptorNotFoundException {
		
		Domain.log("isCollection:uri="+uri, LOG_CHANNEL, Logger.DEBUG);
		boolean isCollection = false;
		
		NodeRevisionDescriptors nrds = null;
		NodeRevisionDescriptor nrd = null;
	
		nrds = content.retrieve(slideToken, uri);
		nrd = content.retrieve(slideToken, nrds);
		
		String _isCollection = nrd.getProperty(NodeRevisionDescriptor.RESOURCE_TYPE).getValue().toString();
		isCollection = _isCollection.indexOf(QuotaConstants.TYPE_COLLECTION) != -1;
		
		Domain.log("isCollection:"+isCollection, LOG_CHANNEL, Logger.DEBUG);
		return isCollection;
		
	}// isCollection
	
	
	/**
	 * Basic QuotaElement constructor
	 * @param uri - resource uri
	 * @param slideToken - token
	 * @param content - content
	 * @throws ObjectNotFoundException
	 */
	public QuotaElement (String uri, SlideToken slideToken, Content content) throws ObjectNotFoundException {
		
		Domain.log("QuotaElement: "+uri, LOG_CHANNEL, Logger.DEBUG);
		
		if (uri == null || slideToken == null || content == null) throw new ObjectNotFoundException("null");

		// removing security
		this.slideToken = new SlideTokenWrapper(slideToken);
		this.slideToken.setForceSecurity(false);
		this.slideToken.setForceLock(false);
		
		this.content = content;
		this.uri = uri;
		
	}// QuotaElement
	
	
	/**
	 * 
	 * QuotaElement with a given content length
	 * 
	 * @param uri - resource uri
	 * @param slideToken - token
	 * @param content - content
	 * @param contentLength - resource content length
	 * @throws AccessDeniedException
	 * @throws LinkedObjectNotFoundException
	 * @throws RevisionDescriptorNotFoundException
	 * @throws ObjectLockedException
	 * @throws ObjectNotFoundException
	 * @throws ServiceAccessException
	 * @throws VetoException
	 */
	public QuotaElement (String uri, SlideToken slideToken, Content content, String contentLength) throws 
	AccessDeniedException, 
	LinkedObjectNotFoundException, 
	RevisionDescriptorNotFoundException, 
	ObjectLockedException, 
	ObjectNotFoundException, 
	ServiceAccessException, 
	VetoException {
		
		Domain.log("QuotaElement: "+uri, LOG_CHANNEL, Logger.DEBUG);
		
		if (uri == null || slideToken == null || content == null) throw new ObjectNotFoundException("null");
		
		// removing security
		this.slideToken = new SlideTokenWrapper(slideToken);
		this.slideToken.setForceSecurity(false);
		this.slideToken.setForceLock(false);
		
		this.content = content;
		this.uri = uri;
		this.quotaExceeded = false;
		this.hasQuota = false;

		this.contentLength = contentLength;
		Domain.log("QuotaElement: content length for "+uri+" SET TO "+this.contentLength, LOG_CHANNEL, Logger.DEBUG);
		
	}// QuotaElement
	
	
	/**
	 * 
	 * QuotaElement with a given content length
	 * 
	 * @param uri - resource uri
	 * @param abstractWebdavMethod - method in progress
	 * @param contentLength - resource content length
	 * @throws AccessDeniedException
	 * @throws LinkedObjectNotFoundException
	 * @throws RevisionDescriptorNotFoundException
	 * @throws ObjectLockedException
	 * @throws ObjectNotFoundException
	 * @throws ServiceAccessException
	 * @throws VetoException
	 */
	public QuotaElement (String uri, AbstractWebdavMethod abstractWebdavMethod, String contentLength) throws 
	AccessDeniedException, 
	LinkedObjectNotFoundException, 
	RevisionDescriptorNotFoundException, 
	ObjectLockedException, 
	ObjectNotFoundException, 
	ServiceAccessException, 
	VetoException {
		
		Domain.log("QuotaElement: "+uri, LOG_CHANNEL, Logger.DEBUG);
		
		if (uri == null || abstractWebdavMethod == null) throw new ObjectNotFoundException("null");
		
		// removing security
		this.slideToken = new SlideTokenWrapper(abstractWebdavMethod.getSlideToken());
		this.slideToken.setForceSecurity(false);
		this.slideToken.setForceLock(false);
		
		this.content = abstractWebdavMethod.getContent();
		this.uri = uri;
		this.quotaExceeded = false;
		this.hasQuota = false;

		this.contentLength = contentLength;
		Domain.log("QuotaElement: content length for "+uri+" SET TO "+this.contentLength, LOG_CHANNEL, Logger.DEBUG);
		
	}// QuotaElement
	
	
	/**
	 * 
	 * QuotaElement with the content length automatically get from the request or NRD
	 * 
	 * @param uri - resource uri
	 * @param abstractWebdavMethod - method in progress
	 * @param contentLengthLocation = CONTENT_LENGTH_IN_NRD | CONTENT_LENGTH_IN_REQUEST
	 * @throws AccessDeniedException
	 * @throws LinkedObjectNotFoundException
	 * @throws RevisionDescriptorNotFoundException
	 * @throws ObjectLockedException
	 * @throws ServiceAccessException
	 * @throws VetoException
	 * @throws ObjectNotFoundException
	 * @throws IOException
	 */
	public QuotaElement (String uri, AbstractWebdavMethod abstractWebdavMethod, Integer contentLengthLocation) throws 
	AccessDeniedException, 
	LinkedObjectNotFoundException, 
	RevisionDescriptorNotFoundException, 
	ObjectLockedException, 
	ServiceAccessException, 
	VetoException, 
	ObjectNotFoundException,
	IOException {
		
		Domain.log("QuotaElement: "+uri, LOG_CHANNEL, Logger.DEBUG);
		
		if (uri == null || abstractWebdavMethod == null) throw new ObjectNotFoundException("null");
		
		// removing security
		this.slideToken = new SlideTokenWrapper(abstractWebdavMethod.getSlideToken());
		this.slideToken.setForceSecurity(false);
		this.slideToken.setForceLock(false);
		
		this.content = abstractWebdavMethod.getContent();
		this.uri = uri;
		this.quotaExceeded = false;
		this.hasQuota = false;
		
		NodeRevisionDescriptors nrds = null;
		NodeRevisionDescriptor nrd = null;
		NodeProperty tmpPropertyAvailableBytes = null;
		NodeProperty tmpPropertyUsedBytes = null;
		
		if (contentLengthLocation == QuotaConstants.CONTENT_LENGTH_IN_NRD) {
			nrds = content.retrieve(slideToken, uri);
			nrd = content.retrieve(slideToken, nrds);
			String _isCollection = nrd.getProperty(NodeRevisionDescriptor.RESOURCE_TYPE).getValue().toString();
			isCollection = _isCollection.indexOf(QuotaConstants.TYPE_COLLECTION) != -1;
			if (isCollection) Domain.log("QuotaElement:"+uri+" is a collection", LOG_CHANNEL, Logger.DEBUG);
		}// if (contentLengthLocation == QuotaConstants.CONTENT_LENGTH_IN_NRD)
		
		if (contentLengthLocation == QuotaConstants.CONTENT_LENGTH_IN_NRD) {
			if (isCollection) {
				NodeProperty propertyCollectionLength = nrd.getProperty(QuotaConstants.NRD_COLLECTION_LENGTH, QuotaConstants.NAMESPACE_ESUP);
				if (propertyCollectionLength != null) this.contentLength = propertyCollectionLength.getValue().toString();
				else this.contentLength = "0";
			}// if (isCollection)
			else this.contentLength = (nrd.getProperty(QuotaConstants.NRD_CONTENT_LENGTH, QuotaConstants.NAMESPACE_DAV).getValue()).toString();
			Domain.log("QuotaElement:content length (in nrd) for "+uri+" = "+this.contentLength, LOG_CHANNEL, Logger.DEBUG);
		}// if (contentLengthLocation == CONTENT_LENGTH_IN_NRD)
		else {
			this.contentLength = String.valueOf(abstractWebdavMethod.getRequest().getContentLength());
			
			if (this.contentLength == "-1") {
			 // Do nothing... Soft quota management					
			}// if (this.contentLength == -1)
			
			Domain.log("QuotaElement:content length (in request) for "+uri+" = "+this.contentLength, LOG_CHANNEL, Logger.DEBUG);
		}// else (contentLengthLocation == CONTENT_LENGTH_IN_NRD)
		
	}// constructor

	
	/**
	 * 
	 * Check if the action to be done leads to an overquota
	 * 
	 * @throws AccessDeniedException
	 * @throws LinkedObjectNotFoundException
	 * @throws RevisionDescriptorNotFoundException
	 * @throws ObjectLockedException
	 * @throws ServiceAccessException
	 * @throws VetoException
	 */
	public void initStorageAction() throws 
	AccessDeniedException, 
	LinkedObjectNotFoundException, 
	RevisionDescriptorNotFoundException, 
	ObjectLockedException, 
	ServiceAccessException, 
	VetoException {
		
		Domain.log("initStorageAction", LOG_CHANNEL, Logger.DEBUG);
		
		NodeRevisionDescriptors nrds = null;
		NodeRevisionDescriptor nrd = null;
		NodeProperty tmpPropertyAvailableBytes = null;
		NodeProperty tmpPropertyUsedBytes = null;
		NodeProperty tmpPropertyVirtualRoot = null;
		
		//////////////////////////////////////////////////////////////////////////
		// checking if the resource already exists and its original content length
		//
		NodeProperty tmpPropertyOriginalContentLength = null;
		String originalContentLength = "0";
		try {
			nrds = this.content.retrieve(slideToken, uri);
			if (nrds != null) nrd = this.content.retrieve(slideToken, nrds);
			if (nrd != null) tmpPropertyOriginalContentLength = nrd.getProperty(QuotaConstants.NRD_CONTENT_LENGTH, QuotaConstants.NAMESPACE_DAV);
			if (tmpPropertyOriginalContentLength != null) {
				originalContentLength = tmpPropertyOriginalContentLength.getValue().toString();
				Domain.log("initStorageAction:resource "+uri+" already exist - originalContentLength="+originalContentLength, LOG_CHANNEL, Logger.DEBUG);
			}// if (tmpPropertyOriginalContentLength != null)
		} catch (ObjectNotFoundException e1) {
			Domain.log("initStorageAction:resource "+uri+" does NOT exist");
		} catch (AccessDeniedException e1) {
//			 what should be done here ?
		} catch (LinkedObjectNotFoundException e1) {
//			 what should be done here ?
		} catch (ObjectLockedException e1) {
//			 what should be done here ?
		} catch (ServiceAccessException e1) {
//			 what should be done here ?
		} catch (VetoException e1) {
//			 what should be done here ?
		}
		
		///////////////////////////
		// Is the action possible ?
		//
		boolean rootNodeReached;
		boolean virtualRoot = false;
		
		if (uri.equalsIgnoreCase("/")) rootNodeReached = true;
		else rootNodeReached = false;
		
		String quotaAvailableBytes = null;
		String quotaUsedBytes = null;
					
		String currentUri = uri;
		
		// loop until the root node (or virtual root) is reached or one quota is exceeded 
		while (!rootNodeReached && !this.quotaExceeded) {
			
			Domain.log("initStorageAction:finding quota MD for "+currentUri, LOG_CHANNEL, Logger.DEBUG);
			
			try {
				nrds = content.retrieve(slideToken, currentUri);;
				nrd = content.retrieve(slideToken, nrds);
				tmpPropertyAvailableBytes = nrd.getProperty(QuotaConstants.QUOTA_AVAILABLE_BYTES, QuotaConstants.NAMESPACE_DAV);
				tmpPropertyUsedBytes = nrd.getProperty(QuotaConstants.QUOTA_USED_BYTES, QuotaConstants.NAMESPACE_DAV);
				tmpPropertyVirtualRoot = nrd.getProperty(QuotaConstants.VIRTUAL_ROOT, QuotaConstants.NAMESPACE_ESUP);
				// checking that the properties are protected - security reason
				if (tmpPropertyAvailableBytes != null && tmpPropertyUsedBytes != null && tmpPropertyVirtualRoot != null) {
					if (!tmpPropertyAvailableBytes.isProtected() || !tmpPropertyUsedBytes.isProtected() || !tmpPropertyVirtualRoot.isProtected()){
						Domain.log("initStorageAction:>> WARNING unprotected quota properties found for "+currentUri+" - these properties are ignored <<", LOG_CHANNEL, Logger.DEBUG);
						tmpPropertyAvailableBytes = null;
						tmpPropertyUsedBytes = null;
					}// if (!tmpPropertyAvailableBytes.isProtected() || !tmpPropertyUsedBytes.isProtected())
				}// if (tmpPropertyAvailableBytes != null && tmpPropertyUsedBytes != null )
				
				if (tmpPropertyVirtualRoot == null) virtualRoot = false;
				else virtualRoot = Boolean.valueOf((String)tmpPropertyVirtualRoot.getValue()).booleanValue();
			} catch (ObjectNotFoundException e) {
				Domain.log("initStorageAction:node "+currentUri+" does not exist - getting parent", LOG_CHANNEL, Logger.DEBUG);
			}
			
			if (tmpPropertyAvailableBytes != null && tmpPropertyUsedBytes != null) {
				this.hasQuota = true;
				
				quotaAvailableBytes = (String) tmpPropertyAvailableBytes.getValue();
				quotaUsedBytes = (String) tmpPropertyUsedBytes.getValue();
				Domain.log("initStorageAction:quota MD found for "+currentUri, LOG_CHANNEL, Logger.DEBUG);
				Domain.log("initStorageAction:..quota-available-bytes="+quotaAvailableBytes, LOG_CHANNEL, Logger.DEBUG);
				Domain.log("initStorageAction:..quota-used-bytes="+quotaUsedBytes, LOG_CHANNEL, Logger.DEBUG);
				Domain.log("initStorageAction:..virtual-root="+virtualRoot, LOG_CHANNEL, Logger.DEBUG);
				
				//if ((Integer.parseInt(quotaAvailableBytes) - (Integer.parseInt(quotaUsedBytes) + (Integer.parseInt(this.contentLength)) - (Integer.parseInt(originalContentLength)))) <= 0) {
				if ((Integer.parseInt(quotaAvailableBytes) - (Integer.parseInt(this.contentLength)) + (Integer.parseInt(originalContentLength))) <= 0) {
					this.quotaExceeded = true;
					Domain.log("initStorageAction:>>>> quota exceeded for node "+currentUri+" <<<<", LOG_CHANNEL, Logger.DEBUG);
				}// if ((Integer.parseInt(quotaAvailableBytes)...
					
			}// if (tmpPropertyAvailableBytes =! null && tmpPropertyUsedBytes != null)
			
			currentUri = QuotaConstants.getParentUri(currentUri);
			if (currentUri.equalsIgnoreCase("/") || virtualRoot) rootNodeReached = true;
			
		} // while (!quotaMetadataFound) {
		
//		if (quotaMetadataFound) {
//			
//			Domain.log("QuotaElement:calculating parent level for "+uri, LOG_CHANNEL, Logger.DEBUG);
//			
//			firstParentContainingQuotaMetadata = currentUri;
//			// calculating the parentLevel
//			if (uri.equalsIgnoreCase(firstParentContainingQuotaMetadata)) parentLevel = 0;
//			else {
//				String uriDiff = uri.substring(firstParentContainingQuotaMetadata.length());
//				String uriDiffReplaced = uriDiff.replaceAll("/", "");
//				parentLevel = uriDiff.length()-uriDiffReplaced.length();
//				Domain.log("QuotaElement:..uriDiff="+uriDiff, LOG_CHANNEL, Logger.DEBUG);
//				Domain.log("QuotaElement:..uriDiffReplaced="+uriDiffReplaced, LOG_CHANNEL, Logger.DEBUG);
//				Domain.log("QuotaElement:parentLevel="+parentLevel, LOG_CHANNEL, Logger.DEBUG);
//				
//			}// (uri.equalsIgnoreCase(firstParentContainingQuotaMetadata))
//			
//		}// if (quotaMetadataFound)
//		else Domain.log("QuotaElement:no quota properties found for "+uri, LOG_CHANNEL, Logger.DEBUG);
		
	} // initStorageAction
	
	/**
	 * Return a description of this quotaElement
	 */
	public String toString() {
		StringBuffer result = new StringBuffer();
		result.append("QuotaElement:");
		result.append(" uri="+uri);
		result.append(" contentLength="+contentLength);
		result.append(" hasQuota="+hasQuota);
		result.append(" quotaExceeded="+quotaExceeded);
		return result.toString();			
	}// toString
	
	
	/**
	 * @return true if this resource has quota
	 */
	public boolean hasQuota() {
		return hasQuota;
	}// quotaFound
	
	
	/**
	 * 
	 * Update quota MD on this quotaElement
	 * 
	 * @param operator = SUBTRACT_QUOTA_USED_BYTES | ADD_QUOTA_USED_BYTES
	 * @param goToRootNode = true | false - true only used currently
	 * @throws ObjectNotFoundException
	 * @throws AccessDeniedException
	 * @throws LinkedObjectNotFoundException
	 * @throws RevisionDescriptorNotFoundException
	 * @throws ObjectLockedException
	 * @throws RevisionNotFoundException
	 * @throws ServiceAccessException
	 * @throws VetoException
	 */
	public void updateQuotaMetadata (String operator, boolean goToRootNode) throws 
	ObjectNotFoundException, 
	AccessDeniedException, 
	LinkedObjectNotFoundException, 
	RevisionDescriptorNotFoundException, 
	ObjectLockedException, 
	RevisionNotFoundException, 
	ServiceAccessException, 
	VetoException {
		
		Domain.log("updateQuotaMetadata:operator="+operator+" goToRootNode="+goToRootNode, LOG_CHANNEL, Logger.DEBUG);
		
		////////////////////////////////
		// trying to find quota metadata
		//
		boolean quotaMetadataFound = false;
		boolean rootNodeReached;
		boolean virtualRoot = false;
		boolean isCollection = false;
		
		if (uri.equalsIgnoreCase("/")) rootNodeReached = true;
		else rootNodeReached = false;
		
		String quotaAvailableBytes = null;
		String quotaUsedBytes = null;
					
		String currentUri = uri;
		
		while (!rootNodeReached) {
			
			Domain.log("updateQuotaMetadata:finding quota MD for "+currentUri, LOG_CHANNEL, Logger.DEBUG);
			
			NodeRevisionDescriptors nrds = null;
			NodeRevisionDescriptor nrd = null;
			NodeProperty tmpPropertyAvailableBytes = null;
			NodeProperty tmpPropertyUsedBytes = null;
			NodeProperty tmpPropertyVirtualRoot = null;
			NodeProperty tmpPropertyIsCollection = null;
			
			try {
				nrds = content.retrieve(slideToken, currentUri);;
				nrd = content.retrieve(slideToken, nrds);
				tmpPropertyAvailableBytes = nrd.getProperty(QuotaConstants.QUOTA_AVAILABLE_BYTES, QuotaConstants.NAMESPACE_DAV);
				tmpPropertyUsedBytes = nrd.getProperty(QuotaConstants.QUOTA_USED_BYTES, QuotaConstants.NAMESPACE_DAV);
				tmpPropertyVirtualRoot = nrd.getProperty(QuotaConstants.VIRTUAL_ROOT, QuotaConstants.NAMESPACE_ESUP);
				tmpPropertyIsCollection = nrd.getProperty(NodeRevisionDescriptor.RESOURCE_TYPE);
				
				// is the resource a collection ? needed later...
				if (tmpPropertyIsCollection != null) {
					String _isCollection = tmpPropertyIsCollection.getValue().toString();
					isCollection = _isCollection.indexOf(QuotaConstants.TYPE_COLLECTION) != -1;
				}// if (tmpPropertyCollectionLength != null)
								
				// checking that the properties are protected, so not put by a DAV client
				if (tmpPropertyAvailableBytes != null && tmpPropertyUsedBytes != null && tmpPropertyVirtualRoot != null) {
				if (!tmpPropertyAvailableBytes.isProtected() || !tmpPropertyUsedBytes.isProtected() || !tmpPropertyVirtualRoot.isProtected()){
					Domain.log("initStorageAction:>> WARNING unprotected quota properties found for "+currentUri+" - these properties are ignored <<", LOG_CHANNEL, Logger.DEBUG);
					tmpPropertyAvailableBytes = null;
					tmpPropertyUsedBytes = null;
				}// if (!tmpPropertyAvailableBytes.isProtected() || !tmpPropertyUsedBytes.isProtected())
				}// if (tmpPropertyAvailableBytes != null && tmpPropertyUsedBytes != null )
				
				if (tmpPropertyVirtualRoot == null) virtualRoot = false;
				else virtualRoot = Boolean.valueOf((String)tmpPropertyVirtualRoot.getValue()).booleanValue();
			} catch (ObjectNotFoundException e) {
				Domain.log("updateQuotaMetadata:node "+currentUri+" does not exist - getting parent", LOG_CHANNEL, Logger.DEBUG);
			}
			
			if (tmpPropertyAvailableBytes != null && tmpPropertyUsedBytes != null) {
				quotaMetadataFound = true;	
				quotaAvailableBytes = (String) tmpPropertyAvailableBytes.getValue();
				quotaUsedBytes = (String) tmpPropertyUsedBytes.getValue();
				Domain.log("updateQuotaMetadata:quota MD found for "+currentUri, LOG_CHANNEL, Logger.DEBUG);
				Domain.log("updateQuotaMetadata:..quota-available-bytes="+quotaAvailableBytes, LOG_CHANNEL, Logger.DEBUG);
				Domain.log("updateQuotaMetadata:..quota-used-bytes="+quotaUsedBytes, LOG_CHANNEL, Logger.DEBUG);
				Domain.log("updateQuotaMetadata:..virtual-root="+virtualRoot, LOG_CHANNEL, Logger.DEBUG);
				
	   			// updating the quota-used-bytes and quota-available-bytes properties
    			int newQuotaUsedBytes = 0;
    			int newQuotaAvailableBytes = 0;
    			if (operator.equals(QuotaConstants.SUBTRACT_QUOTA_USED_BYTES))	{
    				newQuotaUsedBytes = Integer.parseInt(quotaUsedBytes) - Integer.parseInt(this.contentLength);
    				newQuotaAvailableBytes = Integer.parseInt(quotaAvailableBytes) + Integer.parseInt(this.contentLength);
    				if (newQuotaUsedBytes <0) newQuotaUsedBytes = 0;
    				// NO !!
    				//if (newQuotaAvailableBytes <0) newQuotaAvailableBytes = 0;
    			}// if (operator.equals(SUBTRACT_QUOTA_USED_BYTES))
    			else {
    				newQuotaUsedBytes = Integer.parseInt(quotaUsedBytes) + Integer.parseInt(this.contentLength);
    				newQuotaAvailableBytes = Integer.parseInt(quotaAvailableBytes) - Integer.parseInt(this.contentLength);
    			}// else (operator.equals(SUBTRACT_QUOTA_USED_BYTES))
    			
//				int newQuotaUsedBytes = 0;
//    			newQuotaUsedBytes = Integer.parseInt(quotaUsedBytes) + (Integer.parseInt(this.futureContentLength) - Integer.parseInt(this.currentContentLength));
//    			if (newQuotaUsedBytes <0) newQuotaUsedBytes = 0;
    			
    			// for old times sake; apple compatibility
    			int AppleByteBlock = 512;
    			int newQuotaUsedBytesApple = newQuotaUsedBytes / AppleByteBlock;
    			int newQuotaAssignedBytesApple = (newQuotaUsedBytes + newQuotaAvailableBytes) / AppleByteBlock;
    			
    			Domain.log("updateQuotaMetadata:updating "+QuotaConstants.QUOTA_USED_BYTES+" MD for "+currentUri+" to "+String.valueOf(newQuotaUsedBytes), LOG_CHANNEL, Logger.DEBUG);
    			Domain.log("updateQuotaMetadata:updating "+QuotaConstants.QUOTA_AVAILABLE_BYTES+" MD for "+currentUri+" to "+String.valueOf(newQuotaAvailableBytes), LOG_CHANNEL, Logger.DEBUG);
    			//nrd.setProperty(QUOTA_USED_BYTES, String.valueOf(newQuotaUsedBytes));
    			nrd.setProperty(new NodeProperty(QuotaConstants.QUOTA_USED_BYTES, String.valueOf(newQuotaUsedBytes), true));
    			nrd.setProperty(new NodeProperty(QuotaConstants.QUOTA_AVAILABLE_BYTES, String.valueOf(newQuotaAvailableBytes), true));
    			content.store(this.slideToken, currentUri, nrd, null);
    			
    			// for old times sake; apple compatibility
    			Domain.log("updateQuotaMetadata:updating "+QuotaConstants.QUOTA_USED_BYTES_APPLE+" MD for "+currentUri+" to "+String.valueOf(newQuotaUsedBytesApple), LOG_CHANNEL, Logger.DEBUG);
    			Domain.log("updateQuotaMetadata:updating "+QuotaConstants.QUOTA_ASSIGNED_BYTES_APPLE+" MD for "+currentUri+" to "+String.valueOf(newQuotaAssignedBytesApple), LOG_CHANNEL, Logger.DEBUG);
    			nrd.setProperty(new NodeProperty(QuotaConstants.QUOTA_USED_BYTES_APPLE, String.valueOf(newQuotaUsedBytesApple), true));
    			nrd.setProperty(new NodeProperty(QuotaConstants.QUOTA_ASSIGNED_BYTES_APPLE, String.valueOf(newQuotaAssignedBytesApple), true));  			
    			
			}// if (tmpPropertyAvailableBytes =! null && tmpPropertyUsedBytes != null)
			
			/////////////////////////////////////////////////////////////////////////////////////
			// Anyway if the resource is a collection, updating the DAV:getcontentlength property
			//
			if(isCollection) {
				Domain.log("updateQuotaMetadata:"+currentUri+" is a collection", LOG_CHANNEL, Logger.DEBUG);
				NodeProperty tmpPropertyCollectionLength = null;
				tmpPropertyCollectionLength = nrd.getProperty(QuotaConstants.NRD_COLLECTION_LENGTH, QuotaConstants.NAMESPACE_ESUP);
				String _collectionLength;
				if (tmpPropertyCollectionLength != null) _collectionLength = tmpPropertyCollectionLength.getValue().toString();
				else _collectionLength = "0";
				int collectionLength = Integer.valueOf(_collectionLength).intValue();
				int newCollectionSize;
				if (operator.equals(QuotaConstants.SUBTRACT_QUOTA_USED_BYTES)) newCollectionSize = collectionLength - Integer.parseInt(this.contentLength);
				else newCollectionSize = collectionLength + Integer.parseInt(this.contentLength);
				Domain.log("updateQuotaMetadata:updating "+QuotaConstants.NRD_COLLECTION_LENGTH+" MD for "+currentUri+" to "+newCollectionSize, LOG_CHANNEL, Logger.DEBUG);
				nrd.setProperty(new NodeProperty(QuotaConstants.NRD_COLLECTION_LENGTH, String.valueOf(newCollectionSize), QuotaConstants.NAMESPACE_ESUP, NodeRevisionDescriptor.COLLECTION_TYPE, true));
				content.store(this.slideToken, currentUri, nrd, null);
			}// if(isCollection)
			
			currentUri = QuotaConstants.getParentUri(currentUri);
			if (currentUri.equalsIgnoreCase("/") || virtualRoot) rootNodeReached = true;
			
		} // while (!quotaMetadataFound) {
		
	}// updateQuotaMetadata
	
	/**
	 * @return true if the quota is exceeded for the current quotaElement
	 */
	public boolean quotaExceeded () {
		return quotaExceeded;
	}// isStorable
	
	/**
	 * @return Returns the uri.
	 */
	public String getUri() {
		return uri;
	}
	
	/**
	 * @return Returns the contentLength.
	 */
	public String getContentLength() {
		return contentLength;
	}
}// quotaElement
