/* Copyright (c) 2010, 2013 Daniel Doubrovkine, Markus Karg, All Rights Reserved
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.  
 */
package com.sun.jna.platform.win32;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;

import com.sun.jna.platform.win32.WinNT.LARGE_INTEGER;

import junit.framework.TestCase;

/**
 * @author dblock[at]dblock[dot]org
 * @author markus[at]headcrashing[dot]eu
 */
public class Kernel32UtilTest extends TestCase {
	
    public static void main(String[] args) throws Exception {
        System.out.println("Computer name: " + Kernel32Util.getComputerName());
        System.out.println("Temp path: " + Kernel32Util.getTempPath());
        // logical drives
        System.out.println("Logical drives: ");
		Collection<String> logicalDrives = Kernel32Util.getLogicalDriveStrings();
		for(String logicalDrive : logicalDrives) {
			// drive type
			System.out.println(" " + logicalDrive + " (" 
					+ Kernel32.INSTANCE.GetDriveType(logicalDrive) + ")");
			// free space
	    	LARGE_INTEGER.ByReference lpFreeBytesAvailable = new LARGE_INTEGER.ByReference(); 
	    	LARGE_INTEGER.ByReference lpTotalNumberOfBytes = new LARGE_INTEGER.ByReference(); 
	    	LARGE_INTEGER.ByReference lpTotalNumberOfFreeBytes = new LARGE_INTEGER.ByReference(); 
	    	if (Kernel32.INSTANCE.GetDiskFreeSpaceEx(logicalDrive, lpFreeBytesAvailable, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes)) {
		    	System.out.println("  Total: " + formatBytes(lpTotalNumberOfBytes.getValue()));
		    	System.out.println("   Free: " + formatBytes(lpTotalNumberOfFreeBytes.getValue()));
	    	}
		}

		junit.textui.TestRunner.run(Kernel32UtilTest.class);
    }

	/**
	 * Format bytes.
	 * @param bytes
	 *  Bytes.
	 * @return
	 *  Rounded string representation of the byte size.
	 */
    private static String formatBytes(long bytes) {
		if (bytes == 1) { // bytes
			return String.format("%d byte", bytes);
		} else if (bytes < 1024) { // bytes
			return String.format("%d bytes", bytes);
		} else if (bytes < 1048576 && bytes % 1024 == 0) { // Kb
			return String.format("%.0f KB", (double) bytes / 1024);
		} else if (bytes < 1048576) { // Kb
			return String.format("%.1f KB", (double) bytes / 1024);
		} else if (bytes % 1048576 == 0 && bytes < 1073741824) { // Mb
			return String.format("%.0f MB", (double) bytes / 1048576);
		} else if (bytes < 1073741824) { // Mb
			return String.format("%.1f MB", (double) bytes / 1048576);
		} else if (bytes % 1073741824 == 0 && bytes < 1099511627776L) { // GB
			return String.format("%.0f GB", (double) bytes / 1073741824);
		} else if (bytes < 1099511627776L ) {
			return String.format("%.1f GB", (double) bytes / 1073741824);
		} else if (bytes % 1099511627776L == 0 && bytes < 1125899906842624L) { // TB
			return String.format("%.0f TB", (double) bytes / 1099511627776L);
		} else if (bytes < 1125899906842624L ) {
			return String.format("%.1f TB", (double) bytes / 1099511627776L);
		} else {
			return String.format("%d bytes", bytes);
		}
    }
    
	public void testGetComputerName() {
		assertTrue(Kernel32Util.getComputerName().length() > 0);
	}
	
	public void testFormatMessageFromLastErrorCode() {
	    assertEquals("The remote server has been paused or is in the process of being started.",
	    		Kernel32Util.formatMessageFromLastErrorCode(W32Errors.ERROR_SHARING_PAUSED));	
	}

	public void testFormatMessageFromHR() {
		assertEquals("The operation completed successfully.",
				Kernel32Util.formatMessage(W32Errors.S_OK));
	}
	
	public void testGetTempPath() {
		assertTrue(Kernel32Util.getTempPath().length() > 0);
	}
	
	public void testGetLogicalDriveStrings() {
	    Collection<String> logicalDrives = Kernel32Util.getLogicalDriveStrings();
		assertTrue("No logical drives found", logicalDrives.size() > 0);
		for(String logicalDrive : logicalDrives) {
			assertTrue("Empty logical drive name in list", logicalDrive.length() > 0);
		}
	}
	
	public void testDeleteFile() throws IOException {
		String filename = Kernel32Util.getTempPath() + "\\FileDoesNotExist.jna";
		File f = new File(filename);
		f.createNewFile();
		Kernel32Util.deleteFile(filename);
	}
	
	public void testGetFileAttributes() throws IOException {
		String filename = Kernel32Util.getTempPath();
		int fileAttributes = Kernel32Util.getFileAttributes(filename);
		assertEquals(WinNT.FILE_ATTRIBUTE_DIRECTORY, fileAttributes & WinNT.FILE_ATTRIBUTE_DIRECTORY);
		File tempFile = File.createTempFile("jna", "tmp");
		tempFile.deleteOnExit();
		int fileAttributes2 = Kernel32Util.getFileAttributes(tempFile.getAbsolutePath());
		tempFile.delete();
		assertEquals(0, fileAttributes2 & WinNT.FILE_ATTRIBUTE_DIRECTORY);
	}
	
    public void testGetEnvironmentVariable() {
    	assertEquals(null, Kernel32Util.getEnvironmentVariable("jna-getenvironment-test"));
    	Kernel32.INSTANCE.SetEnvironmentVariable("jna-getenvironment-test", "42");
    	assertEquals("42", Kernel32Util.getEnvironmentVariable("jna-getenvironment-test"));
    }

    public final void testGetPrivateProfileInt() throws IOException {
        final File tmp = File.createTempFile("testGetPrivateProfileInt", "ini");
        tmp.deleteOnExit();
        final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
        writer.println("[Section]");
        writer.println("existingKey = 123");
        writer.close();

        assertEquals(123, Kernel32Util.getPrivateProfileInt("Section", "existingKey", 456, tmp.getCanonicalPath()));
        assertEquals(456, Kernel32Util.getPrivateProfileInt("Section", "missingKey", 456, tmp.getCanonicalPath()));
    }

    public final void testGetPrivateProfileString() throws IOException {
        final File tmp = File.createTempFile("testGetPrivateProfileString", "ini");
        tmp.deleteOnExit();
        final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
        writer.println("[Section]");
        writer.println("existingKey = ABC");
        writer.close();

        assertEquals("ABC", Kernel32Util.getPrivateProfileString("Section", "existingKey", "DEF", tmp.getCanonicalPath()));
        assertEquals("DEF", Kernel32Util.getPrivateProfileString("Section", "missingKey", "DEF", tmp.getCanonicalPath()));
    }

    public final void testWritePrivateProfileString() throws IOException {
        final File tmp = File.createTempFile("testWritePrivateProfileString", "ini");
        tmp.deleteOnExit();
        final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
        writer.println("[Section]");
        writer.println("existingKey = ABC");
        writer.println("removedKey = JKL");
        writer.close();

        Kernel32Util.writePrivateProfileString("Section", "existingKey", "DEF", tmp.getCanonicalPath());
        Kernel32Util.writePrivateProfileString("Section", "addedKey", "GHI", tmp.getCanonicalPath());
        Kernel32Util.writePrivateProfileString("Section", "removedKey", null, tmp.getCanonicalPath());
        
        final BufferedReader reader = new BufferedReader(new FileReader(tmp));
        assertEquals(reader.readLine(), "[Section]");
        assertTrue(reader.readLine().matches("existingKey\\s*=\\s*DEF"));
        assertTrue(reader.readLine().matches("addedKey\\s*=\\s*GHI"));
        assertEquals(reader.readLine(), null);
        reader.close();
    }
    
    public final void testGetPrivateProfileSection() throws IOException {
        final File tmp = File.createTempFile("testGetPrivateProfileSection", ".ini");
        tmp.deleteOnExit();

        final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
        try {
            writer.println("[X]");
            writer.println("A=1");
            writer.println("foo=bar");
        } finally {
            writer.close();
        }

        final String[] lines = Kernel32Util.getPrivateProfileSection("X", tmp.getCanonicalPath());
        assertEquals(lines.length, 2);
        assertEquals(lines[0], "A=1");
        assertEquals(lines[1], "foo=bar");
    }

    public final void testGetPrivateProfileSectionNames() throws IOException {
        final File tmp = File.createTempFile("testGetPrivateProfileSectionNames", "ini");
        tmp.deleteOnExit();

        final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
        try {
            writer.println("[S1]");
            writer.println("A=1");
            writer.println("B=X");
            writer.println("[S2]");
            writer.println("C=2");
            writer.println("D=Y");
        } finally {
            writer.close();
        }

        String[] sectionNames = Kernel32Util.getPrivateProfileSectionNames(tmp.getCanonicalPath());
        assertEquals(sectionNames.length, 2);
        assertEquals(sectionNames[0], "S1");
        assertEquals(sectionNames[1], "S2");
    }

    public final void testWritePrivateProfileSection() throws IOException {
        final File tmp = File.createTempFile("testWritePrivateProfileSecion", "ini");
        tmp.deleteOnExit();

        final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
        try {
            writer.println("[S1]");
            writer.println("A=1");
            writer.println("B=X");
            writer.println("[S2]");
            writer.println("C=2");
            writer.println("foo=bar");
        } finally {
            writer.close();
        }

        Kernel32Util.writePrivateProfileSection("S1", new String[] { "A=3", "E=Z" }, tmp.getCanonicalPath());

        final BufferedReader reader = new BufferedReader(new FileReader(tmp));
        try {
            assertEquals(reader.readLine(), "[S1]");
            assertEquals(reader.readLine(), "A=3");
            assertEquals(reader.readLine(), "E=Z");
            assertEquals(reader.readLine(), "[S2]");
            assertEquals(reader.readLine(), "C=2");
            assertEquals(reader.readLine(), "foo=bar");
        } finally {
            reader.close();
        }        
    }
}
