/*
 * 
 * Autopsy Forensic Browser
 * 
 * Copyright 2018 Basis Technology Corp.
 * Contact: carrier <at> sleuthkit <dot> org
 * 
 * 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.sleuthkit.autopsy.commonfilesearch;

import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;

/**
 * Defines types which can be used to get some sort of File Instance node (a
 * child of the MD5Node) for use in the common files tree table.
 */
public abstract class FileInstanceNodeGenerator {

    private static final Logger LOGGER = Logger.getLogger(FileInstanceNodeGenerator.class.getName());
    protected Long abstractFileReference;
    protected static Map<Long, AbstractFile> cachedFiles;
    String caseName;
    String dataSource;

    public FileInstanceNodeGenerator(Long abstractFileReference, Map<Long, AbstractFile> cachedFiles, String dataSource, String caseName) {
        this.abstractFileReference = abstractFileReference;
        cachedFiles = cachedFiles;
        this.caseName = caseName;
        this.dataSource = dataSource;
    }
    
    public FileInstanceNodeGenerator(Map<Long, AbstractFile> cachedFiles) {
        this.abstractFileReference = -1L;
        cachedFiles = cachedFiles;
        this.caseName = "";
        this.dataSource = "";
    }

    /**
     * Grab a cached instance of the AbstractFile or grab one from the
     * SleuthkitCase. Use this in implementations of <code>generateNode</code>.
     *
     * @param objectId
     * @param cachedFiles
     * @return AbstractFile which is identical to the file instance generated by
     * implementations of this object
     */
    protected AbstractFile lookupOrCreateAbstractFile() {
        if (cachedFiles.containsKey(this.abstractFileReference)) {
            return cachedFiles.get(this.abstractFileReference);
        } else {
            AbstractFile file = FileInstanceNodeGenerator.loadFileFromSleuthkitCase(this.abstractFileReference);
            cachedFiles.put(this.abstractFileReference, file);
            return file;
        }
    }

    private static AbstractFile loadFileFromSleuthkitCase(Long objectId) {

        Case currentCase;
        try {
            currentCase = Case.getCurrentCaseThrows();

            SleuthkitCase tskDb = currentCase.getSleuthkitCase();

            AbstractFile abstractFile = tskDb.findAllFilesWhere(String.format("obj_id in (%s)", objectId)).get(0);

            return abstractFile;

        } catch (TskCoreException | NoCurrentCaseException ex) {
            LOGGER.log(Level.SEVERE, String.format("Unable to find AbstractFile for record with obj_id: %s.  Node not created.", new Object[]{objectId}), ex);
            return null;
        }
    }

    /**
     * Create a node which is a child of the MD5Node, to be used to display a
     * row in the tree table
     *
     * @return child row node
     */
    public abstract DisplayableItemNode generateNode();
    
    /**
     * Create a list of nodes which are a child of the MD5Node, to be used to display a
     * row in the tree table
     *
     * @return child row node
     */
    public abstract DisplayableItemNode[] generateNodes();

    public String getCaseName() {
        return this.caseName;
    }

    /**
     * Get string name of the data source where this instance appears.
     *
     * @return
     */
    public String getDataSource() {

        /**
         * Even though we could get this from the CR record or the AbstractFile,
         * we want to avoid getting it from the AbstractFile because it would be
         * an extra database roundtrip.
         */
        return this.dataSource;
    }

    public Long getIdenticalFileSleuthkitCaseObjectID() {
        return this.abstractFileReference;
    }

    public static FileInstanceNodeGenerator createInstance(Iterator<FileInstanceNodeGenerator> identicalFileNodeGeneratorIterator, Integer instanceId) throws Exception {

        //Long arbitraryIdenticalAbstractFileId = null;
        return new CentralRepositoryCaseFileInstanceMetadata(instanceId, cachedFiles);

    }
}

@@ -1819,32 +1819,58 @@
 erence;%0A        
+FileInstanceNodeGenerator.
 cachedFiles = ca
@@ -2081,32 +2081,58 @@
  = -1L;%0A        
+FileInstanceNodeGenerator.
 cachedFiles = ca

Fix intracase cache being null.