// Copyright (C) 2003 Daisuke Arai <darai@users.sourceforge.jp>
// Copyright (C) 2010 panacoran <panacoran@users.sourceforge.jp>
// 
// This program is part of Protra.
//
// Protra is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, see <http://www.gnu.org/licenses/>.
// 
// $Id: PtFileTreeView.cs 405 2010-12-09 06:26:20Z panacoran $

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;

namespace PtSim.Controls
{
    /// <summary>
    /// 拡張子がptのファイルのTreeViewを実装するクラス
    /// </summary>
    public partial class PtFileTreeView : TreeView
    {

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public PtFileTreeView()
        {
            InitializeComponent();
        }

        private string root;
        
        /// <summary>
        /// ルートディレクトリを取得または設定する。
        /// </summary>
        public string Root
        {
            get { return root; }
            set
            {
                root = value;
                SetNodes(Nodes, root);
                CheckedPaths = checkedPaths; // チェックボックスの状態を復元する。
            }
        }

        /// <summary>
        /// ディレクトリとファイルを表すノードを設定する。
        /// </summary>
        /// <param name="nodes">追加するTreeNodeCollection</param>
        /// <param name="path">パス</param>
        private void SetNodes(TreeNodeCollection nodes, string path)
        {
            nodes.Clear();
            if (!Directory.Exists(path))
                return;
            foreach (string d in Directory.GetDirectories(path))
            {
                var key = Path.GetFileName(d);
                var node = nodes.Add(key, key, 0, 0);
                SetNodes(node.Nodes, d);
            }
            foreach (string f in Directory.GetFiles(path, "*.pt"))
            {
                var key = Path.GetFileNameWithoutExtension(f);
                nodes.Add(key, key, 2, 2);
            }
        }

        private List<string> checkedPaths = new List<string>();
        private List<string> checkedFiles = new List<string>();
        
        /// <summary>
        /// チェックボックスの押されたノードのパス名の一覧を取得または設定する。
        /// </summary>
        public List<string> CheckedPaths
        {
            get { return checkedPaths; }
            set
            {
                // 空にしてOnAfterCheckで設定する。
                checkedPaths = new List<string>();
                checkedFiles = new List<string>();
                // 指定されたパスを選択状態にする。
                BeginUpdate();
                foreach (var path in value)
                {
                    TreeNodeCollection nodes = Nodes;
                    TreeNode target = null;
                    foreach (var name in path.Split(PathSeparator[0]))
                    {
                        var found = nodes.Find(name, false);
                        if (found.Length == 0)
                            goto NotFound;
                        target = found[0]; // 同じ階層に同じキーは一つ。
                        nodes = target.Nodes;
                    }
                    target.Checked = true;
                    target.EnsureVisible();
                NotFound:;
                }
                EndUpdate();
            }
        }

        /// <summary>
        /// チェックボックスの押されたファイルの一覧を取得する。
        /// </summary>
        public List<string> CheckedFiles
        {
            get
            {
                return checkedFiles;
            }
        }

        /// <summary>
        /// 選択されているファイルの相対パスを取得する。
        /// </summary>
        public string SelectedRelativeFile
        {
            get
            {
                if (SelectedNode == null)
                    return null;
                string result = SelectedNode.FullPath + ".pt";
                if (!File.Exists(Path.Combine(root, result)))
                    return null;
                return result;
            }
        }

        /// <summary>
        /// BeforeExpandイベントを処理する。
        /// </summary>
        /// <param name="e">BeforeExpandイベントの引数</param>
        protected override void OnBeforeExpand(TreeViewCancelEventArgs e)
        {
            base.OnBeforeExpand(e);
            e.Node.ImageIndex = 1;
            e.Node.SelectedImageIndex = 1;
        }

        /// <summary>
        /// BeforeCollapseイベントを処理する。
        /// </summary>
        /// <param name="e">BeforeCollapseイベントの引数</param>
        protected override void OnBeforeCollapse(TreeViewCancelEventArgs e)
        {
            base.OnBeforeCollapse(e);
            e.Node.ImageIndex = 0;
            e.Node.SelectedImageIndex = 0;
        }

        /// <summary>
        /// AfterCheckイベントを処理する。
        /// </summary>
        /// <param name="e">AfterCheckイベントの引数</param>
        protected override void OnAfterCheck(TreeViewEventArgs e)
        {
            if (e.Action != TreeViewAction.Unknown)
            {
                if (e.Node.Nodes.Count > 0)
                    foreach (TreeNode n in e.Node.Nodes)
                        n.Checked = e.Node.Checked;
                if (!e.Node.Checked && e.Node.Parent != null)
                    e.Node.Parent.Checked = false;
            }
            var path = e.Node.FullPath;
            if (e.Node.Checked)
            {
                if (!CheckedPaths.Contains(path))
                    CheckedPaths.Add(path);
                if (e.Node.ImageIndex == 2) // ファイルの場合
                    if (!CheckedFiles.Contains(path + ".pt"))
                        CheckedFiles.Add(path + ".pt");
            }
            else
            {
                CheckedPaths.Remove(path);
                if (e.Node.ImageIndex == 2)
                    CheckedFiles.Remove(path + ".pt");
            }
            base.OnAfterCheck(e);
        }
    }
}
