/*
 * Copyright (C) 2005-2006 Alfresco, Inc.
 *
 * Licensed under the Mozilla Public License version 1.1 
 * with a permitted attribution clause. You may obtain a
 * copy of the License at
 *
 *   http://www.alfresco.org/legal/license.txt
 *
 * 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.alfresco.filesys.smb.server.repo.pseudo;

import org.alfresco.filesys.server.SrvSession;
import org.alfresco.filesys.server.filesys.FileName;
import org.alfresco.filesys.server.filesys.TreeConnection;
import org.alfresco.filesys.smb.server.SMBSrvSession;
import org.alfresco.filesys.smb.server.repo.ContentContext;
import org.alfresco.filesys.smb.server.repo.FileState;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Content Filesystem Driver Pseudo File Implementation
 *
 * <p>Pseudo file implementation for the content disk driver.
 * 
 * @author gkspencer
 */
public class ContentPseudoFileImpl implements PseudoFileInterface
{
    // Logging
    
    private static final Log logger = LogFactory.getLog(ContentPseudoFileImpl.class);
    
    /**
     * Check if the specified path refers to a pseudo file
     * 
     * @param sess SrvSession
     * @param tree TreeConnection
     * @param path String
     * @return boolean
     */
    public boolean isPseudoFile(SrvSession sess, TreeConnection tree, String path)
    {
        // Check if the path is for a pseudo file
        
        ContentContext ctx = (ContentContext) tree.getContext();
        boolean isPseudo = false;
        
        String[] paths = FileName.splitPath( path);
        FileState fstate = getStateForPath( ctx, paths[0]);
        
        if ( fstate != null && fstate.hasPseudoFiles())
        {
            // Check if there is a matching pseudo file
            
            PseudoFile pfile = fstate.getPseudoFileList().findFile( paths[1], false);
            if ( pfile != null)
                isPseudo = true;
        }
        
        // Return the pseudo file status
        
        return isPseudo;
    }

    /**
     * Return the pseudo file for the specified path, or null if the path is not a pseudo file
     * 
     * @param sess SrvSession
     * @param tree TreeConnection
     * @param path String
     * @return PseudoFile
     */
    public PseudoFile getPseudoFile(SrvSession sess, TreeConnection tree, String path)
    {
        // Check if the path is for a pseudo file
        
        ContentContext ctx = (ContentContext) tree.getContext();
        
        String[] paths = FileName.splitPath( path);
        FileState fstate = getStateForPath( ctx, paths[0]);
        
        if ( fstate != null && fstate.hasPseudoFiles())
        {
            // Check if there is a matching pseudo file
            
            PseudoFile pfile = fstate.getPseudoFileList().findFile( paths[1], false);
            if ( pfile != null)
                return pfile;
        }
        
        // Not a pseudo file
        
        return null;
    }

    /**
     * Add pseudo files to a folder so that they appear in a folder search
     * 
     * @param sess SrvSession
     * @param tree TreeConnection
     * @param path String
     * @return int
     */
    public int addPseudoFilesToFolder(SrvSession sess, TreeConnection tree, String path)
    {
        // Access the device context

        int pseudoCnt = 0;
        ContentContext ctx = (ContentContext) tree.getContext();
        FileState fstate = getStateForPath( ctx, path);

        // Check if pseudo files have already been added for this folder
        
        if ( fstate.hasPseudoFiles())
            return 0;
        
        // Check if this is a CIFS session
        
        boolean isCIFS = sess instanceof SMBSrvSession;
        
        // Add the drag and drop pseudo file, if enabled
        
        if ( isCIFS && ctx.hasDragAndDropApp())
        {
            // If the file state is null create a file state for the path

            if ( fstate == null)
                ctx.getStateTable().findFileState( path, true, true);
            
            // Enable the drag and drop pseudo file
            
            fstate.addPseudoFile( ctx.getDragAndDropApp());

            // Update the count of pseudo files added
            
            pseudoCnt++;
            
            // DEBUG
            
            if ( logger.isInfoEnabled())
                logger.info("Added drag/drop pseudo file for " + path);
        }

        // Add the URL link pseudo file, if enabled
        
        if ( isCIFS && ctx.hasURLFile())
        {
            // Make sure the state has the associated node details
            
            if ( fstate.getNodeRef() != null)
            {
                // Build the URL file data
    
                StringBuilder urlStr = new StringBuilder();
            
                urlStr.append("[InternetShortcut]\r\n");
                urlStr.append("URL=");
                urlStr.append(ctx.getURLPrefix());
                urlStr.append("navigate/browse/workspace/SpacesStore/");
                urlStr.append( fstate.getNodeRef().getId());
                urlStr.append("\r\n");
    
                // Create the in memory pseudo file for the URL link
                
                byte[] urlData = urlStr.toString().getBytes();
                
                MemoryPseudoFile urlFile = new MemoryPseudoFile( ctx.getURLFileName(), urlData);
                fstate.addPseudoFile( urlFile);
                
                // Update the count of files added
                
                pseudoCnt++;
                
                // DEBUG
                
                if ( logger.isInfoEnabled())
                    logger.info("Added URL link pseudo file for " + path);
            }
        }
        
        // Return the count of pseudo files added
        
        return pseudoCnt;
    }

    /**
     * Delete a pseudo file
     * 
     * @param sess SrvSession
     * @param tree TreeConnection
     * @param path String
     */
    public void deletePseudoFile(SrvSession sess, TreeConnection tree, String path)
    {
        // Access the device context

        ContentContext ctx = (ContentContext) tree.getContext();
        
        // Get the file state for the parent folder
        
        String[] paths = FileName.splitPath( path);
        FileState fstate = getStateForPath( ctx, paths[0]);

        // Check if the folder has any pseudo files
        
        if ( fstate == null || fstate.hasPseudoFiles() == false)
            return;

        // Remove the pseudo file from the list
        
        fstate.getPseudoFileList().removeFile( paths[1], false);
    }
    
    /**
     * Return the file state for the specified path
     * 
     * @param ctx ContentContext
     * @param path String
     * @return FileState
     */
    private final FileState getStateForPath(ContentContext ctx, String path)
    {
        // Check if there is a cached state for the path
        
        FileState fstate = null;
        
        if ( ctx.hasStateTable())
        {
            // Get the file state for a file/folder
            
            fstate = ctx.getStateTable().findFileState(path);
        }
        
        // Return the file state
        
        return fstate;
    }
}
