package com.businesslogic.ireport.ui.directorydialog;

import com.ms.wfc.app.*;
import com.ms.wfc.core.*;
import com.ms.wfc.ui.*;
import com.ms.wfc.io.*;
import com.ms.wfc.util.*;
import com.ms.win32.*;
import com.ms.wfc.win32.*;

/**
 * This File Explorer supports drag and drop copying to and from the directory
 * tree, and to and from the filelist. The user cannot move/delete/overwrite
 * anything using this sample. If files are created or deleted in another 
 * application, selecting "Refresh" from the "View" menu will update the view.
 */
public class FileExplorer extends Form  { 
 
    private int mouseDownX, mouseDownY;
	int numb=0;
	String initial_path;
    
    private static final int SHGFI_TYPENAME = 0x0400;
    private static final int SHGFI_SYSICONINDEX = 0x4000;
    private static final int SHGFI_SMALLICON = 0x0001;
    private static final String TITLE_DEFAULT = "iReport Directory Dialog";
    
    private SysImageList sysLargeImageList;
    private SysImageList sysSmallImageList;
    private boolean freshDir;

    private MenuItem[] views;
    
    public FileExplorer(String initial_path) { 
        // Required for Visual J++ Form Designer support
        initForm();		
        fillDirectoryTree();
		this.initial_path = initial_path;
    }

    /**
     * FileExplorer overrides dispose so it can clean up the
     * component list.
     */
    public void dispose() { 
        sysLargeImageList = null;
        sysSmallImageList = null;
        super.dispose();
        components.dispose();
    }
    
    /**
     * Returns a HTML description for this project.
     * 
     * @see WFCRocks.ISample
     */
    public com.ms.wfc.io.IDataStream getHTML() { 
        /*
        * By referencing the file as a resource, it can be embedded in an
        * EXE, DLL, or even be located on a server.  As long as it's in the
        * same location as this class file, we will be able to get it.
        */
        
        return ResourceManager.getResource(getClass(), "FileExplorer.html");
    }
    
    /**
     * For a given root directory (or drive), add the directories to the 
     * directoryTree.
     */
    private void addDirectories(TreeNode node) {
        FileEnumerator e = new FileEnumerator(File.combine(getPathFromNode(node), 
            "*.*"));
        while (e.hasMoreFiles()) {
            String name = e.getName();
            
            /*
            * Keep hidden directories hidden.
            */
            if ((e.getAttributes() & FileAttribute.DIRECTORY) != 0 &&
                (e.getAttributes() & FileAttribute.HIDDEN) == 0) {
                if (!name.equals(".") && !name.equals("..")) {
                    node.addNode(new DirectoryNode(name));
                }
            }
            e.getNextFile();
        }
    }
    
    /**
     * For a given node, add the sub-directories for node's children in the 
     * directoryTree.
     */
    private void addSubDirectories(DirectoryNode node) {
        // Get array of child nodes
        TreeNode[] nodes = node.getNodes();
        for (int i = 0; i < nodes.length; i++) {
            addDirectories(nodes[i]);
        }
        node.subDirectoriesAdded = true;
    }
    


    /**
     *  Internal helper to copy all contents of a directory, including the 
     * contents of subdirectories.
     */ 
    public static boolean copyDirectory(String sourceDir, String destDir) {
        int i = 0;
        File.createDirectories(destDir);
        String path = File.combine(sourceDir, "*.*");
        String[] files = File.getFiles(path);
        try {
            /* 
            * If the directory already exists, it is an exception. This sample
            * will not overwrite anything. 
            */
            for (i = 0; i < files.length; i++) {
                if (!files[i].equals(".") && !files[i].equals("..")) {
                    if (File.isDirectory(File.combine(sourceDir, files[i]))) {
                        copyDirectory(File.combine(sourceDir, files[i]), 
                            File.combine(destDir, files[i]));
                    } else {
                        File.copy(File.combine(sourceDir, files[i]), 
                            File.combine(destDir, files[i]));
                    }
                }
            }
            return true;
        }
        catch (WinIOException winIOE) {
            StringBuffer sMsg = new StringBuffer(
                "This FileExplorer will not overwrite your files. Copy of ");
            sMsg.append(File.combine(destDir, files[i]));
            sMsg.append(" will be aborted.");
            MessageBox.show(sMsg.toString(), "File already exists.", MessageBox.ICONEXCLAMATION);
            return false;
        }
    }

    /** 
     * Event handler for the afterSelect event on the directoryTree. Change the
     * title bar to show the path of the selected directoryNode.
     */
    private void directoryTree_afterSelect(Object source, TreeViewEvent e) {
        StringBuffer text = new StringBuffer(TITLE_DEFAULT);
        text.append(" - ");
        text.append(e.node.getText());
        setText(text.toString());
		this.directory.setText(string_replace("\\","\\\\",e.node.getFullPath()));
		if (numb == 0)
		{
			numb++;
			this.directory.setText(this.initial_path);
		}
    }
	
	public static String string_replace(String s1, String s2, String s3)
 {
	   String string="";
	   string = "";

    	if (s2 == null || s3 == null || s2.length() == 0) return s3;
	   
	   int pos_i = 0; // posizione corrente.
	   int pos_f = 0; // posizione corrente finale
	   
	   int len = s2.length();
	   while ( (pos_f = s3.indexOf(s2, pos_i)) >= 0)
	   {
		   string += s3.substring(pos_i,pos_f)+s1;
		   //+string.substring(pos+ s2.length());
		   pos_f = pos_i = pos_f + len;

	   }

	   string += s3.substring(pos_i);

	   return string;
 }

    /**
     * Event handler for the beforeExpand event on the directoryTree. If the 
     * node is not already expanded, expand it.
     */
    private void directoryTree_beforeExpand(Object source, TreeViewCancelEvent e) {
        DirectoryNode nodeExpanding = (DirectoryNode)e.node;
        if (!nodeExpanding.subDirectoriesAdded)
            addSubDirectories(nodeExpanding);            
    }

    
   




    private void fileExit_click(Object source, Event e) {
        Application.exit();
    }

    /** 
     * Event handler for dropping stuff into the filelist. Directories will 
     * not be accepted.   
     */
    private void fileList_dragDrop(Object source, DragEvent e) {
        if (e.data.getDataPresent(DataFormats.CF_HDROP)) {
            String sourcePath;
            String[] sourceFileName = (String[])e.data.getData(DataFormats.CF_HDROP);
            String destPath = getPathFromNode(directoryTree.getSelectedNode());
            String destFileName;
            boolean abort = false;            

            for (int i = 0; i < sourceFileName.length; ++i){
                // copy items over using system calls
                abort = false;
                sourcePath = File.getDirectory(sourceFileName[i]);

                /*
                * Disallow dragging and dropping into the same folder because that
                * would overwrite                 
                */
                if (sourcePath.equals(destPath)) {
                    return;
                }
                
                destFileName = File.combine(destPath, 
                    File.getName(sourceFileName[i]));
                try  {
                    if (File.isDirectory(sourceFileName[i])) {
                        MessageBox.show( "This is a filelist. You cannot drop a directory here."
                            , "No Directories Allowed!"
                              , MessageBox.ICONEXCLAMATION);
                    } else {
                        File.copy(sourceFileName[i], destFileName);
                    }
                }
                catch (WinIOException winIOE) {
                    // Don't let the user overwrite anything.
                    abort = true;
                    StringBuffer buffy = new StringBuffer("There is already a file, \"");
                    buffy.append(destFileName);
                    buffy.append("\". This file will not be copied.");
                    MessageBox.show( buffy.toString(), "File Already Exists!", 
                        MessageBox.ICONEXCLAMATION);
                }
            }
        }
    }


    /* For initializing the directoryTree upon creation of the FileExplorer. */
    private void fillDirectoryTree() {
        String[] drives = File.getLogicalDrives();
        for (int i = 0; i < drives.length; i++) {
            if (Kernel32.GetDriveType(drives[i]) == win.DRIVE_FIXED ||
				Kernel32.GetDriveType(drives[i]) == win.DRIVE_REMOTE) {
				try {
					DirectoryNode cRoot = new DirectoryNode(drives[i]);
					addDirectories(cRoot);
					directoryTree.addNode(cRoot);
				} catch (Exception ex)
				{}
            }
        }
    }
    
     /**
     * Internal helper to find the node under the cursor in the directoryTree given the 
     * cursor coordinates.
     * 
     * @param - x and y are screen coordinates of the cursor position.
     * @return - node of the directoryTree at (x, y)  
     */
    private TreeNode findNode(int x, int y) { 
        int nodeDesktopX, nodeDesktopY;
        int index = 0;
        boolean foundDir = false;
        boolean foundDrive = false;
        int iconWidth = sysSmallImageList.getImageSize().x;

        TreeNode[] nodes = directoryTree.getNodes();

        /*
        * TreeNode.getBounds() returns client coordinates relative to the form. Since these
        * client coordinates do not take into account the title bar and menu, 
        * we must convert relative coordinates to screen coordinates.
        */ 
        RECT rect = new RECT();
        Windows.GetWindowRect(directoryTree.getHandle(), rect);

        // Find the destination drive and store in nodes[index]
        while (!foundDrive) {
            nodeDesktopY = nodes[index].getBounds().y + rect.top;
            if ((y < nodeDesktopY) && (index < nodes.length)) {
                index++;
            } else {
                foundDrive = true;
            }
        }

        /*
        * This should never happen because findNode(x, y) is only called with
        * (x, y) being a point on the directoryTree.
        */
        if (!foundDrive) {
            return null;
        }
        
        // Find the destination directory and store in next
        TreeNode next = nodes[index];
        while ((next != null) && (foundDir == false)) {
            nodeDesktopY = next.getBounds().y + rect.top;
            nodeDesktopX = next.getBounds().x - iconWidth + rect.left;
            if ((y > nodeDesktopY) && (y < (nodeDesktopY + 
                                            next.getBounds().height))) {
                if((x > nodeDesktopX) && (x < (nodeDesktopX + 
                                               next.getBounds().width + 
                                               iconWidth))) {
                    foundDir = true;
                } else {
                    return null; // Didn't drop on a valid folder
                }
            } else {
                next = (DirectoryNode) next.getNextVisibleNode();
            }
        }            
        return next;
    }

    /**
     *  Returns the directory path of the node.
     */
    private String getPathFromNode(TreeNode node) {
        if (node.getParent() == null) {
            return node.getText();
        }
        return File.combine(getPathFromNode(node.getParent()), node.getText());
    }
    
    /**
     * Overrides control because the samples hash table only recognizes the
     * default title, "WFC File Explorer", in its hash table. You can still
     * explicitly call Control.getText() to get the full text value, which would
     * include the currently selected node.
     *
     * @return default text of the control.
     */
    public String getText() {
        return TITLE_DEFAULT;
    }

    /** 
     * Refresh helper functions to get all expanded nodes under the given
     * node. 
     * 
     * @param expandedNodes - reference to an array of paths containing all 
     * nodes which were in the expanded state when Refresh was requested.
     * 
     * @param startIndex - array index of expandedNodes to start adding entries 
     * to.
     * @return - new startIndex, i.e. given value of startIndex + number of 
     * entries added to expandedNodes.
     */
    private final int refresh_getExpanded(TreeNode node, String[] expandedNodes, int startIndex) {
        if (startIndex < expandedNodes.length) {
            if (node.isExpanded()) {
                expandedNodes[startIndex] = node.getText();
                startIndex++;
                TreeNode[] children = node.getNodes();
                for (int i = 0; i < children.length; i++) {
                    startIndex = refresh_getExpanded(children[i], 
                        expandedNodes,
                        startIndex);
                }
            }
            return startIndex;
        } 
        return -1;
    }
    
    /** 
     * Refresh helper function to expand all nodes whose paths are in paramter 
     * expandedNodes.
     * 
     * @param node - node from which to start expanding.
     * @param expandedNodes - Array of Strings with the path names of all 
     * nodes to expand
     */
    private final void refresh_expand(TreeNode node, String[] expandedNodes) {
        for (int i = expandedNodes.length - 1; i >= 0; i--) {
            if (expandedNodes[i].equals(node.getText())) {
                /*
                * For the expand button to show properly, one level of 
                * invisible children have to be added to the tree. 
                */
                addSubDirectories((DirectoryNode) node);
                node.expand();
                
                /* If the node is expanded, expand any children that were 
                * expanded before the refresh. 
                */
                TreeNode[] children = node.getNodes();
                for (int j = 0; j < children.length; j++) {
                    refresh_expand(children[j], expandedNodes);
                }
                
                return;
            }
        }
    }

    /**
     * Refresh helper function to check if the selected node is one 
     * of the children of a specified node.
     */
    private TreeNode refresh_selected_checkChildren(String selectedNodeString, TreeNode parentNode) {
        if (parentNode.getNodeCount() > 0) {
            if (parentNode.isExpanded()) {
                TreeNode[] children = parentNode.getNodes();
                for (int i = 0; i < children.length; i++) {
                    if (selectedNodeString.equals(children[i].getFullPath())) {
                        return children[i];
                    } else {
                        TreeNode ret = refresh_selected_checkChildren(selectedNodeString, children[i]);
                        if (ret != null) {
                            return ret;
                        }
                    }
                }
            }
        }
        return null;
    }
    
    /**
     * Refreshes the view by deleting all the nodes and restoring them by 
     * reading the disk(s). Any expanded nodes in the directoryView will be 
     * expanded after the refresh.
     * 
     * @param node - Node from which the refresh begins. Generally, this is 
     * the root.
     */
    private void refresh(TreeNode node) {
        // Keep track of which node was selected.
        TreeNode selectedTreeNode = directoryTree.getSelectedNode();
        String selectedTreeNodeString = selectedTreeNode.getFullPath();
        
        /*
        * Update the directoryTree. If there are children, then we must 
        * store the "expanded state" of each. Then we remove all the 
        * children nodes and read them from the system disk again in 
        * case any external application, like the  Windows Explorer, 
        * created/deleted any files/directories.
        */
        if (node.getNodeCount() > 0) {
            if (node.isExpanded()) {
                
                /*
                * Save all expanded nodes rooted at node, even those 
                * that are indirectly rooted. 
                */
                String[] tooBigExpandedNodes = new String[node.getNodeCount(true)];
                int iExpandedNodes = refresh_getExpanded(node, 
                    tooBigExpandedNodes, 
                    0);
                String[] expandedNodes = new String[iExpandedNodes];
                System.arraycopy(tooBigExpandedNodes, 0, expandedNodes, 0, 
                    iExpandedNodes);
                
                node.removeAll();
                addDirectories(node);
                
                /*
                * Make children with subdirectories show up with  
                * expand/collapse button. 
                */
                addSubDirectories((DirectoryNode)node); 
                node.expand();
                
                TreeNode[] children = node.getNodes();
                /*
                * check all children. Some might have had sub-directories 
                * added from an external application so previous childless 
                * nodes might now have children. 
                */
                for (int j = 0; j < children.length; j++) {
                    if (children[j].getNodeCount() > 0) {
                        /*
                        * If the child has subdirectories and it was expanded
                        * before the refresh, then expand after the refresh.                         
                        */
                        refresh_expand(children[j], expandedNodes);
                    }
                }
            } else {
                /* 
                * If the node is not expanded, then there is no need to check
                * if any of the children were expanded. However, we should
                * update the tree by reading the drive in case an external 
                * application add/removed any directories. 
                */
                node.removeAll();
                addDirectories(node);
            }
        } else {
            /* 
            * If there are no children, then again there is no need to 
            * worry about expanded nodes but if an external application
            * add/removed any directories we should reflect that. 
            */
            node.removeAll();
            addDirectories(node);
        }
        
        // setSelectedNode(...) to the node that was selected before the refresh.
        selectedTreeNode 
            = refresh_selected_checkChildren(selectedTreeNodeString, node);
        if (selectedTreeNode != null) {
            directoryTree.setSelectedNode(selectedTreeNode);
        }
    }

    private void viewRefresh_click(Object source, Event e) { 
        TreeNode[] nodes = directoryTree.getNodes();
        for (int i = 0; i < nodes.length; i++) {
            refresh(nodes[i]);
        }
    }

	public String getDirectory()
	{
		return this.directory.getText();
	}
	
	public void setDirectory(String mdir)
	{
		this.directory.setText(mdir);
	}

	private void button1_click(Object source, Event e)
	{
		if (!com.ms.wfc.io.File.exists(this.directory.getText()))
		{
			if (MessageBox.show("La directory non esiste.\nCrearla ora?","",MessageBox.ICONQUESTION|MessageBox.YESNOCANCEL) == DialogResult.YES)
			{
				try {
						com.ms.wfc.io.File.createDirectories(this.directory.getText());
						this.setDialogResult(DialogResult.OK);
						this.setVisible(false);
				} catch (Exception ex)
				{
					MessageBox.show("Impossibile creare la directory specificata!","",MessageBox.ICONERROR);
				}
			}	
			return;
		}
		else
		{
			this.setDialogResult(DialogResult.OK);
			this.setVisible(false);
		}
	}

	/**
	 * NOTE: The following code is required by the Visual J++ form
	 * designer.  It can be modified using the form editor.  Do not
	 * modify it using the code editor.
	 */
	Container components = new Container();
	TreeView directoryTree = new TreeView();
	Splitter splitter1 = new Splitter();
	ImageList imageList1 = new ImageList();
	Panel panel1 = new Panel();
	Button button1 = new Button();
	Edit directory = new Edit();
	Button button2 = new Button();
	GroupBox groupBox1 = new GroupBox();

	private void initForm()
	{
		// NOTA: questo form contiene informazioni relative alle risorse in
		// un file esterno. Non modificare il parametro di tipo String delle
		// chiamate alla funzione resources.getObject(). Ad esempio, non
		// modificare"foo1_location" nella seguente riga di codice,
		// nemmeno se il nome dell'oggetto Foo viene modificato: 
		//	 foo1.setLocation((Point)resources.getObject("foo1_location"));

		IResourceManager resources = new ResourceManager(this, "FileExplorer");
		splitter1.setDock(ControlDock.LEFT);
		splitter1.setSize(new Point(2, 251));
		splitter1.setTabIndex(1);
		splitter1.setTabStop(false);

		imageList1.setImageStream((ImageListStreamer)resources.getObject("imageList1_imageStream"));
		/* @designTimeOnly imageList1.setLocation(new Point(260, 52)); */

		directoryTree.setAllowDrop(true);
		directoryTree.setDock(ControlDock.FILL);
		directoryTree.setLocation(new Point(2, 0));
		directoryTree.setSize(new Point(431, 251));
		directoryTree.setTabIndex(0);
		directoryTree.setText("treeView1");
		directoryTree.setImageList(imageList1);
		directoryTree.setIndent(19);
		directoryTree.setSelectedImageIndex(1);
		directoryTree.setSorted(true);
		directoryTree.addOnAfterSelect(new TreeViewEventHandler(this.directoryTree_afterSelect));
		directoryTree.addOnBeforeExpand(new TreeViewCancelEventHandler(this.directoryTree_beforeExpand));

		panel1.setDock(ControlDock.BOTTOM);
		panel1.setLocation(new Point(0, 251));
		panel1.setSize(new Point(433, 68));
		panel1.setTabIndex(2);
		panel1.setText("panel1");

		button1.setLocation(new Point(276, 40));
		button1.setSize(new Point(75, 24));
		button1.setTabIndex(1);
		button1.setText("Select");
		button1.addOnClick(new EventHandler(this.button1_click));

		directory.setBackColor(Color.CONTROLLIGHTLIGHT);
		directory.setLocation(new Point(4, 4));
		directory.setSize(new Point(424, 20));
		directory.setTabIndex(3);
		directory.setText("");

		button2.setLocation(new Point(356, 40));
		button2.setSize(new Point(75, 24));
		button2.setTabIndex(0);
		button2.setText("Cancel");
		button2.setDialogResult(DialogResult.CANCEL);

		this.setText("iReport Directory Dialog");
		this.setAutoScaleBaseSize(new Point(5, 13));
		this.setBorderStyle(FormBorderStyle.FIXED_DIALOG);
		this.setCancelButton(button2);
		this.setClientSize(new Point(433, 319));
		this.setMaximizeBox(false);
		this.setMinimizeBox(false);

		groupBox1.setLocation(new Point(8, 28));
		groupBox1.setSize(new Point(420, 4));
		groupBox1.setTabIndex(2);
		groupBox1.setTabStop(false);
		groupBox1.setText("");

		this.setNewControls(new Control[] {
							panel1, 
							splitter1, 
							directoryTree});
		panel1.setNewControls(new Control[] {
							  directory, 
							  groupBox1, 
							  button2, 
							  button1});
	}

    /**
     * The main entry point for the application. 
     *
     * @param args Array of parameters passed to the application
     * via the command line.
     */
    public static void main(String args[]) { 
        Application.run(new FileExplorer(null));
    }
}
