/*
 * Autopsy Forensic Browser
 *
 * Copyright 2019 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.contentviewers;

import java.awt.Component;
import java.awt.Cursor;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskCoreException;

/**
 * A file content viewer for HTML files.
 */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer {

    private static final long serialVersionUID = 1L;
    private static final Logger logger = Logger.getLogger(HtmlViewer.class.getName());
    
    private static final String[] SUPPORTED_MIMETYPES = new String[]{
            "text/html",
            "application/xhtml+xml"
    };
    
    /**
     * Creates new form HtmlViewerPanel
     */
    HtmlViewer() {
        initComponents();
    }
    
    /**
     * Retrieve the HTML text content from the supplied file.
     * 
     * @param abstractFile The file to read.
     * 
     * @return The text content of the file.
     */
    private String getHtmlText(AbstractFile abstractFile) {
        try {
            int fileSize = (int) abstractFile.getSize();
            byte[] buffer = new byte[fileSize];
            abstractFile.read(buffer, 0, fileSize);
            return new String(buffer);
        } catch (TskCoreException ex) {
            logger.log(Level.SEVERE, String.format("Unable to read from file '%s' (id=%d).",
                    abstractFile.getName(), abstractFile.getId()), ex);
        }
        
        return null;
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel();

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel;
    // End of variables declaration//GEN-END:variables

    @Override
    public List<String> getSupportedMIMETypes() {
        return Arrays.asList(SUPPORTED_MIMETYPES);
    }

    @Override
    public void setFile(AbstractFile file) {
        WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        htmlPanel.setHtmlText(getHtmlText(file));
        WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
    }

    @Override
    public Component getComponent() {
        return this;
    }

    @Override
    public void resetComponent() {
        htmlPanel.reset();
    }
}

@@ -853,16 +853,50 @@
 .Level;%0A
+import org.openide.util.NbBundle;%0A
 import o
@@ -1862,24 +1862,124 @@
 le.%0A     */%0A
+    @NbBundle.Messages(%7B%0A       %22HtmlViewer_file_error=This file is missing or unreadable.%22,%0A    %7D)%0A
     private 
@@ -2453,39 +2453,88 @@
     
-%7D%0A        %0A        return null;
+    return String.format(%22%3Cp%3E%25s%3C/p%3E%22, Bundle.HtmlViewer_file_error());%0A        %7D
 %0A   
@@ -4225,32 +4225,157 @@
 ETYPES);%0A    %7D%0A%0A
+    @NbBundle.Messages(%7B%0A       %22HtmlViewer_error=This file is not properly formed HTML text that can be displayed.%22,%0A    %7D)%0A
     @Override%0A  
@@ -4523,24 +4523,42 @@
 T_CURSOR));%0A
+        try %7B%0A    
         html
@@ -4591,24 +4591,137 @@
 ext(file));%0A
+        %7D%0A        catch (Exception ex) %7B%0A            htmlPanel.setHtmlText(Bundle.HtmlViewer_error());%0A        %7D%0A
         Wind

Handle incorrectly written HTML files.