//Flatten-synchronization
        public void FlatSynchronize(string path, string pattern, bool bRecursive, AIONode subroot)
        {
            //Process
            isProcessing = true;

            DirectoryInfo di = new DirectoryInfo(path);

            if (di.Exists)
            {
                //Create a folder for the path
                AIONode node = new AIONode(new AIOInfo(GenerateFolderID(), di.Name, false));
                //Insert node to subroot;
                InsertCategory(node, subroot);
                //Then synch
                AIONode previousNode = new AIONode();
                FlatSynchronize_R(di, node, ref previousNode, pattern, bRecursive);
                //Fire update logical explorer event
                UpdateLogicalExplorer(node);
            }

            //Execute and insert into database
            aioDb.ExecuteQueueCommand();

            //End process
            isProcessing = false;
        }
        //Fill treenode with its child
        public void FillOneLevelNode(TreeNode treenode, AIONode subroot)
        {
            treenode.Nodes.Clear();

            if (subroot != null)
            {
                //Get first level child
                TreeNode childNode = null;
                AIONode  child     = subroot.childNode;
                while (child != null)
                {
                    if (child.data.isFile == false)
                    {
                        childNode = new TreeNode();
                        treenode.Nodes.Add(childNode);
                        CopyNodeInfo(childNode, child);
                        //Save container
                        child.container = childNode;

                        //Add blank node for childNode (to show + if has child)
                        if (child.childNode != null)
                        {
                            childNode.Nodes.Add(new TreeNode());
                        }
                    }
                    child = child.nextNode;
                }
            }
        }
 public void CreateRoot(string rootname)
 {
     root         = new AIONode(new AIOInfo(GenerateFolderID(), rootname, false));
     totalCount   = 1;
     foldersCount = 1;
     filesCount   = 0;
 }
        public void MoveNode(AIONode nodeToMove, AIONode nodeToAttach)
        {
            if (nodeToAttach != null && nodeToAttach.data.isFile == false)
            {
                AIONode previousNode     = nodeToMove.prevNode;
                bool    previousIsParent = nodeToMove.prevIsParent;
                //Cut old node
                if (previousIsParent)
                {
                    previousNode.childNode = nodeToMove.nextNode;
                }
                else
                {
                    previousNode.nextNode = nodeToMove.nextNode;
                }
                if (nodeToMove.nextNode != null)
                {
                    nodeToMove.nextNode.prevNode     = nodeToMove.prevNode;
                    nodeToMove.nextNode.prevIsParent = nodeToMove.prevIsParent;
                }

                //Attach into new parent
                if (nodeToAttach.childNode != null)
                {
                    nodeToAttach.childNode.prevNode     = nodeToMove;
                    nodeToAttach.childNode.prevIsParent = false;
                }

                nodeToMove.nextNode     = nodeToAttach.childNode;
                nodeToMove.prevNode     = nodeToAttach;
                nodeToMove.prevIsParent = true;
                nodeToAttach.childNode  = nodeToMove;
            }
        }
 //CreateTreeNode
 public void CopyNodeInfo(TreeNode treenode, AIONode aionode)
 {
     //if (aionode.data != null)
     treenode.Text = aionode.data.Name;
     //treenode.Text = aionode.data.ID;
     //else treenode.Text = "*_*";
     treenode.Tag = aionode;
 }
        public void Sort(AIONode subroot)
        {
            AIONode current = subroot.childNode;

            while (current != null)
            {
            }
        }
        public void Clone(AIONode src, string newID)
        {
            //	if (this.data == null)
            //		this.data = new AIOInfo(newID, true);

            this.data.Clone(src.data);
            this.data.ID = newID;
        }
        private void Swap(AIONode node1, AIONode node2)
        {
            AIONode prev1         = node1.prevNode;
            bool    prev1IsParent = node1.prevIsParent;
            AIONode next1         = node1.nextNode;

            AIONode prev2         = node2.prevNode;
            bool    prev2IsParent = node2.prevIsParent;
            AIONode next2         = node2.nextNode;

            //Swap link
            //Huong toi
            //Node2
            if (prev1IsParent)
            {
                prev1.childNode = node2;
            }
            else
            {
                prev1.nextNode = node2;
            }

            node2.nextNode = next1;

            //Node1
            if (prev2IsParent)
            {
                prev2.childNode = node1;
            }
            else
            {
                prev2.nextNode = node1;
            }

            node1.nextNode = next2;

            //Huong lui
            //Node1
            node1.prevNode     = prev2;
            node1.prevIsParent = prev2IsParent;

            if (next2 != null)
            {
                next2.prevNode = node1;
            }

            //Node2
            node2.prevNode     = prev1;
            node2.prevIsParent = prev1IsParent;

            if (next1 != null)
            {
                next1.prevNode = node2;
            }

            //Swap data
            //???
        }
        public bool IsValidMoveCopy(AIONode nodeToMoveCopy, AIONode nodeToAttach)
        {
            if (nodeToMoveCopy.Equals(nodeToAttach))             //Truong hop 2 node trung nhau
            {
                return(false);
            }

            return(IsValidMoveCopy_R(nodeToMoveCopy.childNode, nodeToAttach));
        }
        public AIONode GetParent(AIONode node)
        {
            AIONode current = node;

            while (current.prevIsParent == false)
            {
                current = current.prevNode;
            }
            return(current.prevNode);
        }
        public AIONode(AIOInfo data)
        {
            //this.info = info;
            //this.isFile = isFile;
            this.data = data;

            prevNode     = null;
            childNode    = null;
            nextNode     = null;
            prevIsParent = false;
        }
        public frmSynchronizeWizard(AIOFolderTree tree2, AIONode subroot)
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            //
            // TODO: Add any constructor code after InitializeComponent call
            //
            this.tree = tree2;
            this.subroot = subroot;
        }
 public void PrintTree_R(AIONode subRoot, ArrayList list)
 {
     //list.Add(subRoot.info.FullName);
     list.Add(subRoot.data.Name);
     if (subRoot.childNode != null)
     {
         PrintTree_R(subRoot.childNode, list);
     }
     if (subRoot.nextNode != null)
     {
         PrintTree_R(subRoot.nextNode, list);
     }
 }
        public void InsertCategory(AIONode nodeToInsert, AIONode nodeToAttach)
        {
            nodeToInsert.nextNode = nodeToAttach.childNode;

            if (nodeToAttach.childNode != null)
            {
                nodeToAttach.childNode.prevNode     = nodeToInsert;
                nodeToAttach.childNode.prevIsParent = false;
            }

            nodeToInsert.prevIsParent = true;
            nodeToInsert.prevNode     = nodeToAttach;

            nodeToAttach.childNode = nodeToInsert;
        }
        private void ApplySynchronization_R(AIONode subroot, string parentPath)
        {
            if (subroot == null)
            {
                return;
            }

/*
 *                      if (subroot.childNode != null)
 *                      {
 *                              DirectoryInfo dir = new DirectoryInfo(parentPath + @"\" + subroot.data.Name);
 *                              if (dir.Exists == false)
 *                                      dir.Create();
 *
 *                              ApplySynchronization_R(subroot.childNode, parentPath + @"\" + subroot.data.Name);
 *                      }*/

            //Apply to subroot
            AIONode current = subroot;

            while (current != null)
            {
                //Apply to folder
                if (current.data.isFile == false)
                {
                    DirectoryInfo dir = new DirectoryInfo(parentPath + @"\" + current.data.Name);
                    if (dir.Exists == false)
                    {
                        dir.Create();
                    }

                    //if (current.Equals(subroot) == false)
                    ApplySynchronization_R(current.childNode, parentPath + @"\" + current.data.Name);
                }
                else
                {
                    //Get file path
                    AIOCommonInfo info = controller.Select(current.data.ID);
                    currentProcessingFile = info.path;

                    //Copy the file to new directory
                    FileInfo file = new FileInfo(info.path);
                    file.CopyTo(parentPath + @"\" + file.Name, bOverwrite);
                }
                //Next
                current = current.nextNode;
            }
        }
        public void InsertFile(AIONode nodeToInsert, AIONode nodeToAttach, string path)
        {
            nodeToInsert.nextNode = nodeToAttach.childNode;

            if (nodeToAttach.childNode != null)
            {
                nodeToAttach.childNode.prevNode     = nodeToInsert;
                nodeToAttach.childNode.prevIsParent = false;
            }

            nodeToInsert.prevIsParent = true;
            nodeToInsert.prevNode     = nodeToAttach;

            nodeToAttach.childNode = nodeToInsert;

            //Database
            QueueNodeInsert(nodeToInsert.data.ID, path);
        }
        private void CopyNode_R(AIONode dest, AIONode src)
        {
            if (src == null)
            {
                return;
            }
            //Copy
            if (src.data.isFile)
            {
                filesCount++;
                dest.Clone(src, GenerateFileID());
            }
            else
            {
                foldersCount++;
                dest.Clone(src, GenerateFolderID());
            }
            //Copy child
            if (src.childNode != null)
            {
                AIONode child = new AIONode();
                CopyNode_R(child, src.childNode);
                dest.childNode     = child;
                child.prevNode     = dest;
                child.prevIsParent = true;

                //Database
                //CopyInfo cho giong nhau giua 2 ID
                QueueNodeCopy(src.childNode.data.ID, child.data.ID);
            }

            if (src.nextNode != null)
            {
                AIONode next = new AIONode();
                CopyNode_R(next, src.nextNode);
                dest.nextNode     = next;
                next.prevNode     = dest;
                next.prevIsParent = false;

                //Database
                //CopyInfo cho giong nhau giua 2 ID
                QueueNodeCopy(src.nextNode.data.ID, next.data.ID);
            }
        }
        public void DeleteNode(AIONode nodeToDelete)
        {
            //Check if nodeToDelete is rootNode
            if (nodeToDelete.Equals(root))
            {
                throw new AIOException(AIOExceptionType.CANNOT_DELETE_ROOT);
            }

            deleteNode = true;
            //Count
            int [] minus = Count(nodeToDelete);
            deleteNode = false;

            foldersCount -= minus[0];
            filesCount   -= minus[1];

            AIONode previousNode = nodeToDelete.prevNode;

            if (previousNode != null)             //Not to delete the root
            {
                bool previousIsParent = nodeToDelete.prevIsParent;
                if (previousIsParent)
                {
                    previousNode.childNode = nodeToDelete.nextNode;
                }
                else
                {
                    previousNode.nextNode = nodeToDelete.nextNode;
                }

                if (nodeToDelete.nextNode != null)
                {
                    nodeToDelete.nextNode.prevIsParent = previousIsParent;
                    nodeToDelete.nextNode.prevNode     = previousNode;
                }
            }

            //Delete
            nodeToDelete = null;

            //Execute Queue Command
            aioDb.ExecuteQueueCommand();
        }
        //Apply Synchronization------------------------------------------
        public void ApplySynchronization(AIONode subroot, string folderPath)
        {
            isProcessing = true;

            //Create folder inside the folderPath
            DirectoryInfo dir = new DirectoryInfo(folderPath);

            dir.CreateSubdirectory(subroot.data.Name);

            string parentPath = folderPath + @"\" + subroot.data.Name;

            dir = new DirectoryInfo(parentPath);
            if (dir.Exists == false)
            {
                dir.Create();
            }

            ApplySynchronization_R(subroot.childNode, parentPath);

            isProcessing = false;
        }
        public void FillTree_R(TreeNode node, AIONode subroot)
        {
            if (subroot == null)
            {
                return;
            }
            CopyNodeInfo(node, subroot);

            if (subroot.childNode != null && subroot.childNode.data.isFile == false)
            {
                TreeNode child = new TreeNode();
                node.Nodes.Add(child);
                FillTree_R(child, subroot.childNode);
            }

            if (subroot.nextNode != null && subroot.nextNode.data.isFile == false)
            {
                TreeNode next = new TreeNode();
                node.Parent.Nodes.Add(next);
                FillTree_R(next, subroot.nextNode);
            }
        }
        //De quy vao cac con de kiem tra destination co phai con cua source hay ko
        private bool IsValidMoveCopy_R(AIONode subroot, AIONode nodeToAttach)
        {
            if (subroot == null)
            {
                return(true);
            }
            if (subroot.Equals(nodeToAttach)) //Invalid
            {
                return(false);
            }
            bool valid = IsValidMoveCopy_R(subroot.childNode, nodeToAttach);

            if (!valid)
            {
                return(false);
            }
            valid = IsValidMoveCopy_R(subroot.nextNode, nodeToAttach);
            if (!valid)
            {
                return(false);
            }
            return(true);
        }
        private void Count_R(AIONode subroot, ref int folderCount, ref int fileCount)
        {
            //Dem tat ca cac con cua subroot
            if (subroot == null)
            {
                return;
            }
            //Child
            AIONode current = subroot.childNode;

            while (current != null)
            {
                if (current.data.isFile == false)                 //Folder
                {
                    Count_R(current, ref folderCount, ref fileCount);
                    folderCount++;
                    //Save ID
                    if (deleteNode)
                    {
                        queueFolderID.Enqueue(current.data.ID);
                    }
                }
                else
                {
                    fileCount++;
                    if (deleteNode)
                    {
                        //Save ID
                        queueFileID.Enqueue(current.data.ID);
                        //Database
                        QueueNodeDelete(current.data.ID);
                    }
                }

                current = current.nextNode;
            }
        }
        public int[] Count(AIONode subroot)
        {
            int [] fCount = { 0, 0 };
            //f[0] //Folder
            //f[1] //File
            if (deleteNode)             //Delete node thi can dem luon chinh no'
            {
                if (subroot.data.isFile)
                {
                    fCount[1] = 1;
                }
                else
                {
                    fCount[0] = 1;
                }
            }

            //Save ID if delete
            if (deleteNode)
            {
                if (subroot.data.isFile)
                {
                    //Save ID for later use
                    queueFileID.Enqueue(subroot.data.ID);
                    //Database
                    QueueNodeDelete(subroot.data.ID);
                }
                else
                {
                    queueFolderID.Enqueue(subroot.data.ID);
                }
            }

            Count_R(subroot, ref fCount[0], ref fCount[1]);
            return(fCount);
        }
        private void Count_R(AIONode subroot, ref int folderCount, ref int fileCount)
        {
            //Dem tat ca cac con cua subroot
            if (subroot == null) return;
            //Child
            AIONode current = subroot.childNode;

            while (current != null)
            {
                if (current.data.isFile == false) //Folder
                {
                    Count_R(current, ref folderCount , ref fileCount);
                    folderCount++;
                    //Save ID
                    if (deleteNode)
                        queueFolderID.Enqueue(current.data.ID);
                }
                else
                {
                    fileCount++;
                    if (deleteNode)
                    {
                        //Save ID
                        queueFileID.Enqueue(current.data.ID);
                        //Database
                        QueueNodeDelete(current.data.ID);
                    }
                }

                current = current.nextNode;
            }
        }
        public void Synchronize(string path, string pattern, bool bRecursive, AIONode subroot)
        {
            //Process
            isProcessing = true;

            DirectoryInfo di = new DirectoryInfo(path);
            if (di.Exists)
            {
                //Create a folder for the path
                AIONode node = new AIONode(new AIOInfo(GenerateFolderID(), di.Name, false));
                //Insert node to subroot;
                InsertCategory(node, subroot);
                //Then synch
                Synchronize_R(di, node, pattern, bRecursive);
                //Fire update logical explorer event
                UpdateLogicalExplorer(node);
            }

            //ExecuteQueue to insert file information into database
            aioDb.ExecuteQueueCommand();

            //End process
            isProcessing = false;
        }
 //De quy vao cac con de kiem tra destination co phai con cua source hay ko
 private bool IsValidMoveCopy_R(AIONode subroot, AIONode nodeToAttach)
 {
     if (subroot == null) return true;
     if (subroot.Equals(nodeToAttach)) //Invalid
         return false;
     bool valid = IsValidMoveCopy_R(subroot.childNode, nodeToAttach);
     if (!valid) return false;
     valid = IsValidMoveCopy_R(subroot.nextNode, nodeToAttach);
     if (!valid) return false;
     return true;
 }
        //Fill treenode with its child
        public void FillOneLevelNode(TreeNode treenode, AIONode subroot)
        {
            treenode.Nodes.Clear();

            if (subroot != null) {
                //Get first level child
                TreeNode childNode = null;
                AIONode child = subroot.childNode;
                while (child != null) {
                    if (child.data.isFile == false)
                    {
                        childNode = new TreeNode();
                        treenode.Nodes.Add(childNode);
                        CopyNodeInfo(childNode, child);
                        //Save container
                        child.container = childNode;

                        //Add blank node for childNode (to show + if has child)
                        if (child.childNode != null)
                            childNode.Nodes.Add(new TreeNode());
                    }
                    child = child.nextNode;
                }
            }
        }
        private void ApplySynchronization_R(AIONode subroot, string parentPath)
        {
            if (subroot == null) return;
            /*
            if (subroot.childNode != null)
            {
                DirectoryInfo dir = new DirectoryInfo(parentPath + @"\" + subroot.data.Name);
                if (dir.Exists == false)
                    dir.Create();

                ApplySynchronization_R(subroot.childNode, parentPath + @"\" + subroot.data.Name);
            }*/

            //Apply to subroot
            AIONode current = subroot;

            while (current != null)
            {
                //Apply to folder
                if (current.data.isFile == false)
                {
                    DirectoryInfo dir = new DirectoryInfo(parentPath + @"\" + current.data.Name);
                    if (dir.Exists == false)
                        dir.Create();

                    //if (current.Equals(subroot) == false)
                    ApplySynchronization_R(current.childNode, parentPath + @"\" + current.data.Name);
                }
                else
                {
                    //Get file path
                    AIOCommonInfo info = controller.Select(current.data.ID);
                    currentProcessingFile = info.path;

                    //Copy the file to new directory
                    FileInfo file = new FileInfo(info.path);
                    file.CopyTo(parentPath+@"\"+file.Name, bOverwrite);
                }
                //Next
                current = current.nextNode;
            }
        }
 public void CreateRoot(string rootname)
 {
     root = new AIONode(new AIOInfo(GenerateFolderID(), rootname, false));
     totalCount = 1;
     foldersCount = 1;
     filesCount = 0;
 }
        //AIONode previousNode = null;
        public void FlatSynchronize_R(DirectoryInfo di, AIONode subroot, ref AIONode previousNode, string pattern, bool bRecursive)
        {
            //DirectoryInfo di = (DirectoryInfo)subRoot.info;
            DirectoryInfo [] subDi = di.GetDirectories();
            if (subDi.Length > 0)             //Co thu muc con
            {
                if (bRecursive)
                {
                    for (int i = 0; i < subDi.Length; i++)
                    {
                        //Recursive
                        FlatSynchronize_R(subDi[i], subroot, ref previousNode, pattern, bRecursive);
                    }
                    //Sau vong lap nay, curChild se tro toi node thu muc cuoi cung
                    //Neu doi curChild (2 dong cuoi) ra ngoai, curChild se tro ve null
                    //preChild se chi luon toi node cuoi sau khi het vong lap
                }
            }

            //Duyet het file va tra ve
            FileInfo [] fileInfo = di.GetFiles(pattern);
            if (fileInfo.Length > 0)
            {
                totalCount += fileInfo.Length;
                AIOProgress.progressValue = filesCount / 100;
                Thread.Sleep(1);
                //FirstNode
                filesCount++;
                AIONode firstChild = new AIONode(new AIOInfo(GenerateFileID(), fileInfo[0].Name, true));
                //Database
                QueueNodeInsert(firstChild.data.ID, fileInfo[0].FullName);

                if (subroot.childNode == null)                 //Khong co thu muc con, chi co file
                {
                    subroot.childNode       = firstChild;
                    firstChild.prevNode     = subroot;
                    firstChild.prevIsParent = true;
                }
                else                 //Co thu muc con
                {
                    previousNode.nextNode   = firstChild;
                    firstChild.prevNode     = previousNode;
                    firstChild.prevIsParent = false;
                }

                previousNode = firstChild;

                //Check xem file na`o thoa, bat dau tu firstChild
                AIONode curChild = null;
                for (int i = 1; i < fileInfo.Length; i++)
                {
                    filesCount++;
                    curChild = new AIONode(new AIOInfo(GenerateFileID(), fileInfo[i].Name, true));
                    //Database
                    QueueNodeInsert(curChild.data.ID, fileInfo[i].FullName);

                    previousNode.nextNode = curChild;
                    curChild.prevNode     = previousNode;
                    curChild.prevIsParent = false;

                    //Update previousNode;
                    previousNode = curChild;
                }
            }
        }
        public bool IsValidMoveCopy(AIONode nodeToMoveCopy, AIONode nodeToAttach)
        {
            if (nodeToMoveCopy.Equals(nodeToAttach)) //Truong hop 2 node trung nhau
                return false;

            return IsValidMoveCopy_R(nodeToMoveCopy.childNode, nodeToAttach);
        }
        public void MoveNode(AIONode nodeToMove, AIONode nodeToAttach)
        {
            if (nodeToAttach != null && nodeToAttach.data.isFile == false) {
                AIONode previousNode = nodeToMove.prevNode;
                bool previousIsParent = nodeToMove.prevIsParent;
                //Cut old node
                if (previousIsParent) {
                    previousNode.childNode = nodeToMove.nextNode;
                } else {
                    previousNode.nextNode = nodeToMove.nextNode;
                }
                if (nodeToMove.nextNode != null) {
                    nodeToMove.nextNode.prevNode = nodeToMove.prevNode;
                    nodeToMove.nextNode.prevIsParent = nodeToMove.prevIsParent;
                }

                //Attach into new parent
                if (nodeToAttach.childNode != null)
                {
                    nodeToAttach.childNode.prevNode = nodeToMove;
                    nodeToAttach.childNode.prevIsParent = false;
                }

                nodeToMove.nextNode = nodeToAttach.childNode;
                nodeToMove.prevNode = nodeToAttach;
                nodeToMove.prevIsParent = true;
                nodeToAttach.childNode = nodeToMove;
            }
        }
        public void Synchronize_R(DirectoryInfo di, AIONode subRoot, string pattern, bool bRecursive)
        {
            //DirectoryInfo di = (DirectoryInfo)subRoot.info;
            DirectoryInfo [] subDi    = di.GetDirectories();
            AIONode          curChild = null;
            AIONode          preChild = null;

            if (subDi.Length > 0)             //Co thu muc con
            {
                totalCount += subDi.Length;
                AIOProgress.progressValue = foldersCount / 100;
                Thread.Sleep(1);

                if (bRecursive)
                {
                    //First Child
                    foldersCount++;

                    AIONode firstChild = new AIONode(new AIOInfo(GenerateFolderID(), subDi[0].Name, false));
                    subRoot.childNode = firstChild;
                    //Child
                    curChild = firstChild;
                    for (int i = 0; i < subDi.Length; i++)
                    {
                        //Recursive
                        Synchronize_R(subDi[i], curChild, pattern, bRecursive);

                        //Gan parent pointer
                        if (preChild != null)
                        {
                            curChild.prevNode     = preChild;
                            curChild.prevIsParent = false;
                        }
                        else
                        {
                            curChild.prevNode     = subRoot;
                            curChild.prevIsParent = true;
                        }
                        //Save preChild
                        preChild = curChild;
                        //Move next
                        if (i < subDi.Length - 1)                         //Chi xet toi node ke cuoi
                        {
                            foldersCount++;

                            curChild.nextNode = new AIONode(new AIOInfo(GenerateFolderID(), subDi[i + 1].Name, false));
                            curChild          = curChild.nextNode;
                        }
                    }
                    //Sau vong lap nay, curChild se tro toi node thu muc cuoi cung
                    //Neu doi curChild (2 dong cuoi) ra ngoai, curChild se tro ve null
                    //preChild se chi luon toi node cuoi sau khi het vong lap
                }
            }

            //Duyet het file va tra ve
            FileInfo [] fileInfo = di.GetFiles(pattern);
            if (fileInfo.Length > 0)
            {
                totalCount += fileInfo.Length;
                //FirstNode
                filesCount++;
                AIONode firstChild = new AIONode(new AIOInfo(GenerateFileID(), fileInfo[0].Name, true));
                //QueueCommand
                QueueNodeInsert(firstChild.data.ID, fileInfo[0].FullName);

                if (curChild == null)                 //Khong co thu muc con, chi co file
                {
                    subRoot.childNode = firstChild;
                }
                else                 //Co thu muc con
                {
                    curChild.nextNode = firstChild;
                }
                curChild = firstChild;

                //PreChild
                if (preChild == null)
                {
                    preChild = subRoot;
                }                 //Nguoc lai thi de nguyen

                AIONode next = null;
                //Check xem file na`o thoa, bat dau tu firstChild
                for (int i = 0; i < fileInfo.Length; i++)
                {
                    if (i < fileInfo.Length - 1)
                    {
                        filesCount++;
                        next = new AIONode(new AIOInfo(GenerateFileID(), fileInfo[i + 1].Name, true));
                        //QueueCommand
                        QueueNodeInsert(next.data.ID, fileInfo[i + 1].FullName);
                    }
                    else
                    {
                        next = null;
                    }
                    curChild.nextNode = next;

                    //Prev
                    curChild.prevNode = preChild;
                    if (preChild.Equals(subRoot))
                    {
                        curChild.prevIsParent = true;
                    }
                    else
                    {
                        curChild.prevIsParent = false;
                    }

                    //Next
                    preChild = curChild;
                    curChild = curChild.nextNode;
                }
            }
        }
 public void PrintTree_R(AIONode subRoot, ArrayList list)
 {
     //list.Add(subRoot.info.FullName);
     list.Add(subRoot.data.Name);
     if (subRoot.childNode != null)
     {
         PrintTree_R(subRoot.childNode, list);
     }
     if (subRoot.nextNode != null)
     {
         PrintTree_R(subRoot.nextNode, list);
     }
 }
        private void CopyNode_R(AIONode dest, AIONode src)
        {
            if (src == null) return;
            //Copy
            if (src.data.isFile) {
                filesCount++;
                dest.Clone(src, GenerateFileID());
            }
            else
            {
                foldersCount++;
                dest.Clone(src, GenerateFolderID());
            }
            //Copy child
            if (src.childNode != null)
            {
                AIONode child = new AIONode();
                CopyNode_R(child, src.childNode);
                dest.childNode = child;
                child.prevNode = dest;
                child.prevIsParent = true;

                //Database
                //CopyInfo cho giong nhau giua 2 ID
                QueueNodeCopy(src.childNode.data.ID, child.data.ID);
            }

            if (src.nextNode != null)
            {
                AIONode next = new AIONode();
                CopyNode_R(next, src.nextNode);
                dest.nextNode = next;
                next.prevNode = dest;
                next.prevIsParent = false;

                //Database
                //CopyInfo cho giong nhau giua 2 ID
                QueueNodeCopy(src.nextNode.data.ID, next.data.ID);
            }
        }
        //AIONode previousNode = null;
        public void FlatSynchronize_R(DirectoryInfo di, AIONode subroot, ref AIONode previousNode, string pattern, bool bRecursive)
        {
            //DirectoryInfo di = (DirectoryInfo)subRoot.info;
            DirectoryInfo [] subDi = di.GetDirectories();
            if (subDi.Length > 0) //Co thu muc con
            {
                if (bRecursive)
                {
                    for (int i = 0;i<subDi.Length;i++)
                    {
                        //Recursive
                        FlatSynchronize_R(subDi[i], subroot, ref previousNode, pattern, bRecursive);
                    }
                    //Sau vong lap nay, curChild se tro toi node thu muc cuoi cung
                    //Neu doi curChild (2 dong cuoi) ra ngoai, curChild se tro ve null
                    //preChild se chi luon toi node cuoi sau khi het vong lap
                }
            }

            //Duyet het file va tra ve
            FileInfo [] fileInfo = di.GetFiles(pattern);
            if (fileInfo.Length > 0)
            {
                totalCount += fileInfo.Length;
                AIOProgress.progressValue = filesCount / 100;
                Thread.Sleep(1);
                //FirstNode
                filesCount++;
                AIONode firstChild = new AIONode(new AIOInfo(GenerateFileID(), fileInfo[0].Name, true));
                //Database
                QueueNodeInsert(firstChild.data.ID, fileInfo[0].FullName);

                if (subroot.childNode == null) //Khong co thu muc con, chi co file
                {
                    subroot.childNode = firstChild;
                    firstChild.prevNode = subroot;
                    firstChild.prevIsParent = true;
                }
                else //Co thu muc con
                {
                    previousNode.nextNode = firstChild;
                    firstChild.prevNode = previousNode;
                    firstChild.prevIsParent = false;
                }

                previousNode = firstChild;

                //Check xem file na`o thoa, bat dau tu firstChild
                AIONode curChild = null;
                for (int i = 1;i<fileInfo.Length;i++)
                {
                    filesCount++;
                    curChild = new AIONode(new AIOInfo(GenerateFileID(), fileInfo[i].Name, true));
                    //Database
                    QueueNodeInsert(curChild.data.ID, fileInfo[i].FullName);

                    previousNode.nextNode = curChild;
                    curChild.prevNode = previousNode;
                    curChild.prevIsParent = false;

                    //Update previousNode;
                    previousNode = curChild;
                }
            }
        }
        //Tree view drapdrop
        private void treeView1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (((e.Button & MouseButtons.Left) == MouseButtons.Left) && !IsDragDroping)
            {
                TreeNode treeNode = treeView1.SelectedNode;
                if (treeNode == null) return;

                AIONode node = (AIONode)treeNode.Tag;
                AIONode [] nodes = new AIONode[] {node};

                IsDragDroping = true;
                //ddType = DragDropType.TREE;

                previousSelected = treeView1.SelectedNode;

                //Copy or Move
                treeView1.DoDragDrop(nodes, DragDropEffects.Copy | DragDropEffects.Move);
            }
        }
        public void FillTree_R(TreeNode node, AIONode subroot)
        {
            if (subroot == null) return;
            CopyNodeInfo(node, subroot);

            if (subroot.childNode != null && subroot.childNode.data.isFile == false)
            {
                TreeNode child = new TreeNode();
                node.Nodes.Add(child);
                FillTree_R(child, subroot.childNode);
            }

            if (subroot.nextNode != null && subroot.nextNode.data.isFile == false)
            {
                TreeNode next = new TreeNode();
                node.Parent.Nodes.Add(next);
                FillTree_R(next, subroot.nextNode);
            }
        }
        public void InsertFileIntoSelectedNode(string path)
        {
            TreeNode node = treeView1.SelectedNode;
            if (node == null) return;

            //Insert new category
            AIONode nodeToAttach = (AIONode)node.Tag;

            tree.FilesCount++;

            string name = AIOUtil.GetNameFromPath(path);
            AIONode nodeToInsert = new AIONode(new AIOInfo(tree.GenerateFileID(), name, true));

            tree.InsertFile(nodeToInsert, nodeToAttach, path);

            //Be sure to execute the queue
            aioDb.ExecuteQueueCommand();

            //Update listview
            UpdateListView();
        }
        public void Synchronize_R(DirectoryInfo di, AIONode subRoot, string pattern, bool bRecursive)
        {
            //DirectoryInfo di = (DirectoryInfo)subRoot.info;
            DirectoryInfo [] subDi = di.GetDirectories();
            AIONode curChild = null;
            AIONode preChild = null;
            if (subDi.Length > 0) //Co thu muc con
            {
                totalCount += subDi.Length;
                AIOProgress.progressValue = foldersCount / 100;
                Thread.Sleep(1);

                if (bRecursive)
                {
                    //First Child
                    foldersCount++;

                    AIONode firstChild = new AIONode(new AIOInfo(GenerateFolderID(), subDi[0].Name, false));
                    subRoot.childNode = firstChild;
                    //Child
                    curChild = firstChild;
                    for (int i = 0;i<subDi.Length;i++)
                    {
                        //Recursive
                        Synchronize_R(subDi[i], curChild, pattern, bRecursive);

                        //Gan parent pointer
                        if (preChild != null)
                        {
                            curChild.prevNode = preChild;
                            curChild.prevIsParent = false;
                        }
                        else
                        {
                            curChild.prevNode = subRoot;
                            curChild.prevIsParent = true;
                        }
                        //Save preChild
                        preChild = curChild;
                        //Move next
                        if (i < subDi.Length - 1) //Chi xet toi node ke cuoi
                        {
                            foldersCount++;

                            curChild.nextNode = new AIONode(new AIOInfo(GenerateFolderID(), subDi[i+1].Name, false));
                            curChild = curChild.nextNode;
                        }

                    }
                    //Sau vong lap nay, curChild se tro toi node thu muc cuoi cung
                    //Neu doi curChild (2 dong cuoi) ra ngoai, curChild se tro ve null
                    //preChild se chi luon toi node cuoi sau khi het vong lap
                }
            }

            //Duyet het file va tra ve
            FileInfo [] fileInfo = di.GetFiles(pattern);
            if (fileInfo.Length > 0)
            {
                totalCount += fileInfo.Length;
                //FirstNode
                filesCount++;
                AIONode firstChild = new AIONode(new AIOInfo(GenerateFileID(), fileInfo[0].Name, true));
                //QueueCommand
                QueueNodeInsert(firstChild.data.ID, fileInfo[0].FullName);

                if (curChild == null) //Khong co thu muc con, chi co file
                {
                    subRoot.childNode = firstChild;
                }
                else //Co thu muc con
                {
                    curChild.nextNode = firstChild;
                }
                curChild = firstChild;

                //PreChild
                if (preChild == null)
                {
                    preChild = subRoot;
                } //Nguoc lai thi de nguyen

                AIONode next = null;
                //Check xem file na`o thoa, bat dau tu firstChild
                for (int i = 0;i<fileInfo.Length;i++)
                {
                    if (i < fileInfo.Length - 1)
                    {
                        filesCount++;
                        next = new AIONode(new AIOInfo(GenerateFileID(), fileInfo[i+1].Name, true));
                        //QueueCommand
                        QueueNodeInsert(next.data.ID, fileInfo[i+1].FullName);
                    }
                    else
                        next = null;
                    curChild.nextNode = next;

                    //Prev
                    curChild.prevNode = preChild;
                    if (preChild.Equals(subRoot))
                        curChild.prevIsParent = true;
                    else
                        curChild.prevIsParent = false;

                    //Next
                    preChild = curChild;
                    curChild = curChild.nextNode;
                }
            }
        }
        private void CreateContainerNode(AIONode node)
        {
            AIONode parent = tree.GetParent(node);
            TreeNode parentNode = (TreeNode)parent.container;

            //Expand to create childnodes and container
            parentNode.Expand();
        }
        private void ctxNew_Click(object sender, System.EventArgs e)
        {
            TreeNode node = treeView1.SelectedNode;
            if (node == null) return;

            node.Expand();

            //Insert new category
            AIONode nodeToAttach = (AIONode)node.Tag;
            tree.FoldersCount++;
            AIONode nodeToInsert = new AIONode(new AIOInfo(tree.GenerateFolderID(), "New Category", false));
            tree.InsertCategory(nodeToInsert, nodeToAttach);

            //Tree
            TreeNode newNode = new TreeNode();
            tree.CopyNodeInfo(newNode, nodeToInsert);

            //Save Container
            nodeToInsert.container = newNode;

            //Insert();
            node.Nodes.Insert(0, newNode);
            if (node.IsExpanded == false)
                node.Expand();

            newNode.BeginEdit();
        }
        private void MoveNode(AIONode [] nodeToMoves, AIONode nodeToAttach)
        {
            for (int i = 0;i<nodeToMoves.Length;i++)
            {
                AIONode nodeToMove = nodeToMoves[i];
                //Logically
                tree.MoveNode(nodeToMove, nodeToAttach);
                //Change tree
                if (nodeToMove.data.isFile == false) //Folder
                {
                    TreeNode toMove = (TreeNode)nodeToMove.container;
                    TreeNode toAttach = (TreeNode)nodeToAttach.container;

                    //Remove old
                    toMove.Remove();

                    //Insert new
                    InsertNode(toAttach, toMove);
                }
            }

            //previousSelected
            treeView1.SelectedNode = previousSelected;

            //Update
            UpdateListView();
        }
        public void DeleteNode(AIONode nodeToDelete)
        {
            //Check if nodeToDelete is rootNode
            if (nodeToDelete.Equals(root)) {
                throw new AIOException(AIOExceptionType.CANNOT_DELETE_ROOT);
            }

            deleteNode = true;
            //Count
            int [] minus = Count(nodeToDelete);
            deleteNode = false;

            foldersCount -= minus[0];
            filesCount -= minus[1];

            AIONode previousNode = nodeToDelete.prevNode;

            if (previousNode != null) //Not to delete the root
            {
                bool previousIsParent = nodeToDelete.prevIsParent;
                if (previousIsParent)
                {
                    previousNode.childNode = nodeToDelete.nextNode;
                }
                else
                {
                    previousNode.nextNode = nodeToDelete.nextNode;
                }

                if (nodeToDelete.nextNode != null)
                {
                    nodeToDelete.nextNode.prevIsParent = previousIsParent;
                    nodeToDelete.nextNode.prevNode = previousNode;
                }
            }

            //Delete
            nodeToDelete = null;

            //Execute Queue Command
            aioDb.ExecuteQueueCommand();
        }
        private void Swap(AIONode node1, AIONode node2)
        {
            AIONode prev1 = node1.prevNode;
            bool prev1IsParent = node1.prevIsParent;
            AIONode next1 = node1.nextNode;

            AIONode prev2 = node2.prevNode;
            bool prev2IsParent = node2.prevIsParent;
            AIONode next2 = node2.nextNode;

            //Swap link
            //Huong toi
            //Node2
            if (prev1IsParent)
                prev1.childNode = node2;
            else
                prev1.nextNode = node2;

            node2.nextNode = next1;

            //Node1
            if (prev2IsParent)
                prev2.childNode = node1;
            else
                prev2.nextNode = node1;

            node1.nextNode = next2;

            //Huong lui
            //Node1
            node1.prevNode = prev2;
            node1.prevIsParent = prev2IsParent;

            if (next2 != null)
                next2.prevNode = node1;

            //Node2
            node2.prevNode = prev1;
            node2.prevIsParent = prev1IsParent;

            if (next1 != null)
                next1.prevNode = node2;

            //Swap data
            //???
        }
        private void tree_UpdateLogicalExplorer(AIONode node)
        {
            TreeNode treenode = new TreeNode();
            tree.CopyNodeInfo(treenode, node);
            //Make container
            node.container = treenode;

            AIONode parent = tree.GetParent(node);
            TreeNode parentnode = (TreeNode)parent.container;

            tree.FillOneLevelNode(treenode, node);
            //Insert to treeView
            //InsertNode(parentnode, treenode);
            //Marshall to STA thread
            treeView1.Invoke(new InsertNodeDele(InsertNode), new object[] {parentnode, treenode});
        }
        public void InsertFile(AIONode nodeToInsert, AIONode nodeToAttach, string path)
        {
            nodeToInsert.nextNode = nodeToAttach.childNode;

            if (nodeToAttach.childNode != null)
            {
                nodeToAttach.childNode.prevNode = nodeToInsert;
                nodeToAttach.childNode.prevIsParent = false;
            }

            nodeToInsert.prevIsParent = true;
            nodeToInsert.prevNode = nodeToAttach;

            nodeToAttach.childNode = nodeToInsert;

            //Database
            QueueNodeInsert(nodeToInsert.data.ID, path);
        }
        private void CopyNode(AIONode [] nodesToCopy, AIONode nodeToAttach)
        {
            for (int i = 0;i<nodesToCopy.Length;i++)
            {
                AIONode nodeToCopy = nodesToCopy[i];

                //Logically
                AIONode newCopy = tree.CopyNode(nodeToCopy, nodeToAttach);
                //Change tree
                if (nodeToCopy.data.isFile == false) //Folder
                {
                    TreeNode toAttach = (TreeNode)nodeToAttach.container;

                    TreeNode newCopyNode = CreateTreeNode(newCopy);
                    //Insert null child for new copy node
                    newCopyNode.Nodes.Insert(0, new TreeNode());

                    //Insert new
                    InsertNode(toAttach, newCopyNode);
                }
            }
            //previousSelected
            treeView1.SelectedNode = previousSelected;

            //Update
            UpdateListView();
        }
        public void InsertCategory(AIONode nodeToInsert, AIONode nodeToAttach)
        {
            nodeToInsert.nextNode = nodeToAttach.childNode;

            if (nodeToAttach.childNode != null)
            {
                nodeToAttach.childNode.prevNode = nodeToInsert;
                nodeToAttach.childNode.prevIsParent = false;
            }

            nodeToInsert.prevIsParent = true;
            nodeToInsert.prevNode = nodeToAttach;

            nodeToAttach.childNode = nodeToInsert;
        }
        //My methods-----------------------------------------------------
        //Create a tree node from AIONode
        private TreeNode CreateTreeNode(AIONode node)
        {
            TreeNode treenode = new TreeNode();
            tree.CopyNodeInfo(treenode, node);

            //Save container
            node.container = treenode;

            return treenode;
        }
 public AIONode GetParent(AIONode node)
 {
     AIONode current = node;
     while (current.prevIsParent == false)
     {
         current = current.prevNode;
     }
     return current.prevNode;
 }
        private void DeleteNode(AIONode [] nodesToDelete)
        {
            for (int i = 0;i<nodesToDelete.Length;i++)
            {
                AIONode nodeToDelete = nodesToDelete[i];

                try
                {
                    tree.DeleteNode(nodeToDelete);

                    if (nodeToDelete.data.isFile == false)
                    {
                        TreeNode toDelete = (TreeNode)nodeToDelete.container;
                        if (toDelete != null)
                            toDelete.Remove();
                    }
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.Message);
                }
            }
            UpdateListView();
        }
        //Return new AIONode
        public AIONode CopyNode(AIONode nodeToCopy, AIONode nodeToAttach)
        {
            if (nodeToAttach != null && nodeToAttach.data.isFile == false)             //Attach to folder
            {
                //AIONode newNode = new AIONode(nodeToCopy.info, nodeToCopy.isFile);
                //newNode.childNode = nodeToCopy.childNode;
                AIONode newNode = new AIONode();
                if (nodeToCopy.data.isFile)
                {
                    filesCount++;
                    newNode.Clone(nodeToCopy, GenerateFileID());

                    //Database
                    //CopyInfo cho giong nhau giua 2 ID
                    QueueNodeCopy(nodeToCopy.data.ID, newNode.data.ID);
                }
                else
                {
                    foldersCount++;
                    newNode.Clone(nodeToCopy, GenerateFolderID());
                }

                if (nodeToCopy.childNode != null)
                {
                    AIONode newChild = new AIONode();

                    //Copy child
                    CopyNode_R(newChild, nodeToCopy.childNode);

                    newNode.childNode = newChild;

                    //Gan lai parant cho newChild
                    //if (newChild != null)
                    //{
                    newChild.prevNode     = newNode;
                    newChild.prevIsParent = true;
                    //}

                    if (newChild.data.isFile)
                    {
                        //Database
                        //CopyInfo cho giong nhau giua 2 ID
                        QueueNodeCopy(nodeToCopy.childNode.data.ID, newChild.data.ID);
                    }
                }

                //----------------Check lai dong nay---------------------



                //Thay doi parent flag
                if (nodeToAttach.childNode != null)
                {
                    nodeToAttach.childNode.prevNode     = newNode;
                    nodeToAttach.childNode.prevIsParent = false;
                }

                newNode.nextNode       = nodeToAttach.childNode;
                newNode.prevNode       = nodeToAttach;
                newNode.prevIsParent   = true;
                nodeToAttach.childNode = newNode;

                //Execute Database Queue Command
                aioDb.ExecuteQueueCommand();

                return(newNode);
            }
            return(null);
        }
        //Delete
        private void treeView1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete) //Delete
            {
                TreeNode node = treeView1.SelectedNode;
                if (node == null) return;

                if (e.Shift == false) //Confirmation
                {
                    DialogResult result = MessageBox.Show("Are you sure?", "Delete", MessageBoxButtons.YesNo);
                    if (result.Equals(DialogResult.No))
                        return;
                }

                AIONode nodeToDelete = (AIONode)node.Tag;
                AIONode [] nodeToDeletes = new AIONode[] {nodeToDelete};

                DeleteNode(nodeToDeletes);
            }
        }
        public void Sort(AIONode subroot)
        {
            AIONode current = subroot.childNode;
            while (current != null)
            {

            }
        }