/*
 * $Id: LnkCreator.java,v 1.5 2006/03/23 11:44:30 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: LnkCreator.java,v $
 * Revision 1.5  2006/03/23 11:44:30  marbobo
 * + Mögliche NPE abgefangen
 *
 * Revision 1.4  2004/11/10 15:02:47  koppy
 * Projektweite Überarbeitung von Error-Logs, Stacktraces,..
 *
 * Revision 1.3  2004/06/24 23:33:32  marbobo
 * Quellcode maintenance
 *
 * Revision 1.2  2004/06/07 14:28:27  lawern
 * Debug-Ausgabe beseitigt.
 *
 * Revision 1.1  2004/06/07 14:13:30  lawern
 * initiale Version
 *
 */
package vkc.util;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

import vkc.misc.VKCLogManager;


/*
 * Erzeugt aus den übergebenen Parametern einen Stream der eine
 * Windows2000-kompatibele LNK-Datei enthält.
 *
 * @author lawern
 */
public final class LnkCreator {
    static boolean debug = false;

    //static String webFolderName = "dav on vilnius.c-lab.de";
    static String webFolderName = "VKC-Webfolder";

    //Kopf der LNK-Datei
    static byte[] lnkHead = {
        0x4c, 0x00, 0x00, 0x00, 0x01, 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
        (byte) 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, (byte) 0x81, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    static byte[] lnkTail = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

    //Unbekannte Felder die aber in jeder LNK-Date, die auf einen DAV-Webfolder verweist 
    //gleich sind.
    static byte[] unknownFields = {
        0x14, 0x00, 0x1f, 0x50, (byte) 0xe0, 0x4f, (byte) 0xd0, 0x20,
        (byte) 0xea, 0x3a, 0x69, 0x10, (byte) 0xa2, (byte) 0xd8, 0x08, 0x00,
        0x2b, 0x30, 0x30, (byte) 0x9d, 0x14, 0x00, 0x2e, (byte) 0x80, 0x00,
        (byte) 0xdf, (byte) 0xea, (byte) 0xbd, 0x65, (byte) 0xc2, (byte) 0xd0,
        0x11, (byte) 0xbc, (byte) 0xed, 0x00, (byte) 0xa0, (byte) 0xc9, 0x0a,
        (byte) 0xb5, 0x0f
    };
    static byte[] rootStringHead = {
        0x4c, 0x50, 0x00, 0x01, 0x42, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
        0x00, 0x00
    };
    static byte[] folderStringHead = {
        0x4c, 0x50, 0x00, 0x02, 0x42, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
        0x00, 0x00
    };
    static byte[] fileStringHead = {
        0x4c, 0x50, 0x00, 0x02, 0x42, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte) 0x80,
        0x00, 0x00, 0x00
    };

    public static ByteArrayInputStream getStream(String rootUrl, String[] path,
        String fileName) {
        if (debug) {
            System.out.println("RootUrl: " + rootUrl);
            System.out.println("FileName: " + fileName);
        }

        return new ByteArrayInputStream(getArray(rootUrl, path, fileName));
    }

    public static byte[] getArray(String rootUrl, String[] path, String fileName) {
        //Body erzeugen
        byte[] body = createContent(rootUrl, path, fileName);

        byte[] result = new byte[body.length + 0x7c];

        //LNK-Head in result-Array kopieren
        System.arraycopy(lnkHead, 0, result, 0, lnkHead.length);

        //Content-Länge codieren
        int contentLength = body.length + unknownFields.length + 2;
        result[lnkHead.length] = (byte) (contentLength % 256);
        result[lnkHead.length + 1] = (byte) (contentLength / 256);

        //Unbekannte Felder in result-Array kopieren
        System.arraycopy(unknownFields, 0, result, lnkHead.length + 2,
            unknownFields.length);

        //Body in result-Array kopieren
        System.arraycopy(body, 0, result,
            lnkHead.length + 2 + unknownFields.length, body.length);

        //Body in result-Array kopieren
        System.arraycopy(lnkTail, 0, result, result.length - 6, lnkTail.length);

        return result;
    }

    /*
     * Erzeugt den variablen Teil der LNK-Datei aus der übergebenen Url.
     */
    private static byte[] createContent(String rootUrl, String[] path,
        String fileName) {
        byte[] rootEntry = createRootEntry(webFolderName, rootUrl);

        byte[] result = rootEntry;
        byte[] folderEntry;

        for (int i = 0; i < path.length; i++) {
            if (debug) {
                System.out.println("PathElement: " + path[i]);
            }

            folderEntry = createFolderEntry(path[i]);
            result = concatenateArrays(result, folderEntry);
        }

        byte[] fileEntry = createFileEntry(fileName);
        result = concatenateArrays(result, fileEntry);

        return result;
    }

    /*
     * Erzeugt den Root-Eintrag, der aus Name des Webfolders und der Root-Url besteht.
     */
    private static byte[] createRootEntry(String webFolderName, String rootUrl) {
        byte[] webFolderNameArray = encodeString(webFolderName);
        byte[] rootUrlArray = encodeString(rootUrl);
        int entryLength = rootStringHead.length + webFolderNameArray.length +
            rootUrlArray.length;
        byte[] result = new byte[entryLength + 2];

        //String-Länge codieren
        result[0] = (byte) (result.length % 256);
        result[1] = (byte) (result.length / 256);

        System.arraycopy(rootStringHead, 0, result, 2, rootStringHead.length);
        System.arraycopy(webFolderNameArray, 0, result,
            rootStringHead.length + 2, webFolderNameArray.length);
        System.arraycopy(rootUrlArray, 0, result,
            rootStringHead.length + webFolderNameArray.length + 2,
            rootUrlArray.length);

        return result;
    }

    /*
     * Erzeugt einen Verzeichniseintrag.
     */
    private static byte[] createFolderEntry(String folderName) {
        return createStringEntry(folderStringHead, folderName);
    }

    /*
     * Erzeugt einen Dateieintrag
     */
    private static byte[] createFileEntry(String fileName) {
        return createStringEntry(fileStringHead, fileName);
    }

    /*
     * Erzeugt einen String-Entry für die LNK-Datei
     */
    private static byte[] createStringEntry(byte[] stringHead, String entry) {
        byte[] entryArray = encodeString(entry);
        int entryLength = entryArray.length + stringHead.length;
        byte[] result = new byte[entryLength + 4];

        //String-Länge codieren
        result[0] = (byte) (result.length % 256);
        result[1] = (byte) (result.length / 256);

        System.arraycopy(stringHead, 0, result, 2, stringHead.length);
        System.arraycopy(entryArray, 0, result, stringHead.length + 2,
            entryArray.length);

        //Entry-Ende codieren
        result[entryLength + 2] = 0;
        result[entryLength + 3] = 0;

        return result;
    }

    /*
     * Codiert einen String in dem für LNK-Dateien notwendigen Format.
     */
    private static byte[] encodeString(String entry) {
        //String in Byte-Array konvertieren
        byte[] stringArray = null;

        try {
            stringArray = entry.getBytes("UTF-16LE");
        } catch (UnsupportedEncodingException e) {
        	stringArray = new byte[0];
        }

        int length = stringArray.length;
        byte[] result = new byte[length + 4];

        //String-Länge codieren
        result[0] = (byte) (entry.length() % 256);
        result[1] = (byte) (entry.length() / 256);

        System.arraycopy(stringArray, 0, result, 2, length);

        //String-Ende codieren
        result[length + 2] = 0;
        result[length + 3] = 0;

        return result;
    }

    /*
     * Konkatiniert 2 Arrays
     */
    private static byte[] concatenateArrays(byte[] array1, byte[] array2) {
        byte[] result = new byte[array1.length + array2.length];
        System.arraycopy(array1, 0, result, 0, array1.length);
        System.arraycopy(array2, 0, result, array1.length, array2.length);

        return result;
    }

    public static void main(String[] args) {
        VKCLogManager.init( "c:/temp/test_", ".log" );
        VKCLogManager.setEnableLogging(true);
        VKCLogManager.setLogToConsole(true);
        
        String[] path = { "User", "Test, User" };
        byte[] testString = getArray("http://vilnius.c-lab.de/dav", path,
                "Schriftauszeichnung.doc");

        for (int i = 0; i < testString.length; i++) {
            System.out.println("0x" + Integer.toHexString(i) + ": 0x" +
                Integer.toHexString(testString[i]));
        }

        try {
            FileUtils.saveByteArray("X:\\html\\test\\vkc.doc.lnk", testString,
                true);
        } catch (IllegalArgumentException e) {
        } catch (IOException e) {
        }
    }
}
