using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace FileListBox_Demo
{
    public partial class FileListBox : UserControl
    {
        #region Pola prywatne
        //wewnetrzne
        private string[] listaKatalogow = null;
        private string[] listaPlikow = null;
        private string[] listaDyskow = null;
        private bool pokazujDwieKropki = true;
        //konfigurowanie komponentu
        private string sciezkaKatalogu = null;
        private bool uwzglednijKatalogi = true;
        private bool uwzglednijPliki = true;
        private bool uwzglednijDyski = true;
        private bool uwzglednijKatalogNadrzedny = true;
        private string filtr = null;
        private bool mozliweZmienianieKatalogow = true;
        #endregion

        #region Metody prywatne
        private void PobierzZawartoscKatalogu()
        {
            if (sciezkaKatalogu==null) 
                sciezkaKatalogu=Directory.GetCurrentDirectory();

            pokazujDwieKropki=(sciezkaKatalogu!=Path.GetPathRoot(sciezkaKatalogu) 
                   && uwzglednijKatalogNadrzedny);

	        if (!Directory.Exists(sciezkaKatalogu))
		        throw new Exception("Katalog "+sciezkaKatalogu+" nie istnieje!");

            listBox1.Items.Clear();

	        if (uwzglednijKatalogi)
		    {
		        if (pokazujDwieKropki) listBox1.Items.Add("[..]");
		        listaKatalogow=Directory.GetDirectories(sciezkaKatalogu);
                Array.Sort(listaKatalogow);
		        //listBox1.Items.AddRange(listaKatalogow);
                foreach (string katalog in listaKatalogow)
                    listBox1.Items.Add("["+Path.GetFileName(katalog)+"]");
		    }
	        if (uwzglednijPliki)
		    {
                if (filtr != null)
                    listaPlikow = Directory.GetFiles(sciezkaKatalogu, filtr);
                else
                    listaPlikow=Directory.GetFiles(sciezkaKatalogu);
                Array.Sort(listaPlikow);
		        //listBox1.Items.AddRange(listaPlikow);
                foreach (string plik in listaPlikow)
                    listBox1.Items.Add(Path.GetFileName(plik));
		    }
	        if (uwzglednijDyski)
		    {
		        listaDyskow=Directory.GetLogicalDrives();
		        //listBox1.Items.AddRange(listaDyskow);
                foreach (string dysk in listaDyskow)
                    listBox1.Items.Add("<" + dysk.Substring(0, 2) + ">");
		    }
        }
        #endregion


        public FileListBox()
        {
            InitializeComponent();
            PobierzZawartoscKatalogu();
        }

        private void listBox1_DoubleClick(object sender, EventArgs e)
        {
            int przesuniecie = (pokazujDwieKropki && uwzglednijKatalogi) ? 1 : 0;
            int numer = listBox1.SelectedIndex - przesuniecie; //+1 dla [..]
            int poczatekPlikow = (uwzglednijKatalogi ? listaKatalogow.Length : 0);
            int poczatekDyskow =
                    poczatekPlikow + (uwzglednijPliki ? listaPlikow.Length : 0);

            //zmiana katalogu
            string nowaSciezkaKatalogu = null;
            if (numer == -1) nowaSciezkaKatalogu = sciezkaKatalogu + "\\..";
            if (numer >= 0 && numer < poczatekPlikow)
                nowaSciezkaKatalogu = listaKatalogow[numer];
            if (numer >= poczatekDyskow) 
                nowaSciezkaKatalogu = listaDyskow[numer-poczatekDyskow];
            if (nowaSciezkaKatalogu != null 
                && Directory.Exists(nowaSciezkaKatalogu)
                && mozliweZmienianieKatalogow)
            {
                sciezkaKatalogu = Path.GetFullPath(nowaSciezkaKatalogu);
                PobierzZawartoscKatalogu();
                OnDirectoryPathChanged(this,e);
            }

            //podwojne klikniecie pliku
            string sciezkaPliku = null;
            if (numer >= poczatekPlikow && numer < poczatekDyskow)
                sciezkaPliku = listaPlikow[numer - poczatekPlikow];
            if (sciezkaPliku != null && File.Exists(sciezkaPliku))
                this.OnFileDoubleClicked(this, e, Path.GetFullPath(sciezkaPliku));
        }

        #region Wlasnosci
        [
	        Category("Directory"),
	        Description("The DirectoryPath determines relative or absolute path of directory visible at component.")
        ]
        public string DirectoryPath
        {
	        set
	        {
		        this.sciezkaKatalogu = value;
		        PobierzZawartoscKatalogu();
                OnDirectoryPathChanged(this,new System.EventArgs());
            }
	        get
	        {
		        return this.sciezkaKatalogu;
	        }
        }

        [
            Category("Directory"),
            Description("The Filter determines the mask of files in the list.")
        ]
        public string Filter
        {
            set
            {
                this.filtr = value;
                PobierzZawartoscKatalogu();
            }
            get
            {
                return this.filtr;
            }
        }

        [
            Category("Directory"),
            Description("The DoubleDotVisible determines if symbol of ***** directory should be displayed.")
        ]
        public bool DoubleDotVisible
        {
            set
            {
                this.uwzglednijKatalogNadrzedny = value;
                PobierzZawartoscKatalogu();
            }
            get
            {
                return this.uwzglednijKatalogNadrzedny;
            }
        }

        [
            Category("Directory"),
            Description("The DirectoriesVisible determines if list of directories should be displayed.")
        ]
        public bool DirectoriesVisible
        {
            set
            {
                this.uwzglednijKatalogi = value;
                PobierzZawartoscKatalogu();
            }
            get
            {
                return this.uwzglednijKatalogi;
            }
        }

        [
            Category("Directory"),
            Description("The FilesVisible determines if list of files should be displayed.")
        ]
        public bool FilesVisible
        {
            set
            {
                this.uwzglednijPliki = value;
                PobierzZawartoscKatalogu();
            }
            get
            {
                return this.uwzglednijPliki;
            }
        }

        [
            Category("Directory"),
            Description("The DrivesVisible determines if list of drives should be displayed.")
        ]
        public bool DrivesVisible
        {
            set
            {
                this.uwzglednijDyski = value;
                PobierzZawartoscKatalogu();
            }
            get
            {
                return this.uwzglednijDyski;
            }
        }

        [
            Category("Directory"),
            Description("The DirectoryChangeAllowed determines if user can change current directory by double-clicking on directory in the list.")
        ]
        public bool DirectoryChangeAllowed
        {
            set
            {
                mozliweZmienianieKatalogow = value;
            }
            get
            {
                return mozliweZmienianieKatalogow;
            }
        }

        [
            Category("Directory"),
            Description("The FileName expose the full path and filename to selected item.")
        ]
        public string FileName
        {
            get
            {
                int przesuniecie=(pokazujDwieKropki && uwzglednijKatalogi)?1:0;
	            int numer=listBox1.SelectedIndex-przesuniecie; //+1 dla [..]
	            int poczatekPlikow=(uwzglednijKatalogi?listaKatalogow.Length:0);
	            int poczatekDyskow=poczatekPlikow+(uwzglednijPliki?listaPlikow.Length:0);

	            string pelnaSciezka=null;
	            if (numer==-1 && przesuniecie==1) 
                    pelnaSciezka=sciezkaKatalogu+"\\..";
	            if (numer>=0 && numer<poczatekPlikow) 
                    pelnaSciezka=listaKatalogow[numer];
	            if (numer>=poczatekPlikow && numer<poczatekDyskow) 
                    pelnaSciezka=listaPlikow[numer-poczatekPlikow];
	            if (numer>=poczatekDyskow) 
                    pelnaSciezka=listaDyskow[numer-poczatekDyskow];

	            if (pelnaSciezka==null) return "";

	            return Path.GetFullPath(pelnaSciezka);
            }
        }
        #endregion

        #region Zdarzenia
        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.OnClick(e);
            this.OnSelectedFileChanged(sender, e);
        }

        //zdarzenie SelectedFileChanged
        public delegate void SelectedFileChangedEventHandler(object sender, EventArgs e);

        [
            Category("Directory"),
            Description("Occures when file selectecion is changed.")
        ]
        public event SelectedFileChangedEventHandler SelectedFileChanged;
        protected virtual void OnSelectedFileChanged(object sender, EventArgs e)
        {
            if (SelectedFileChanged != null) SelectedFileChanged(this, e);
        }

        //zdarzenie DirectoryPathChanged
        [
	        Category("Directory"),
            Description("Occures when directory presented in component is changed.")
        ]
        public event SelectedFileChangedEventHandler DirectoryPathChanged;
        protected virtual void OnDirectoryPathChanged(object sender, EventArgs e)
        {
	        if (DirectoryPathChanged!=null) DirectoryPathChanged(sender,e);
        }

        //Zdarzenie FileDoubleClicked
        public delegate void FileDoubleClickedEventHandler(object sender, EventArgs e, string fileName);
        [
            Category("Directory"),
            Description("Occures when one of the files in the list is double clicked.")
        ]
        public event FileDoubleClickedEventHandler FileDoubleClicked;
        protected virtual void OnFileDoubleClicked(object sender, EventArgs e, string fileName)
        {
            if (FileDoubleClicked != null) FileDoubleClicked(this, e, fileName);
        }

        #endregion

        private void listBox1_MouseDown(object sender, MouseEventArgs e)
        {
            this.OnMouseDown(e);
        }

        private void listBox1_MouseEnter(object sender, EventArgs e)
        {
            this.OnMouseEnter(e);
        }

        private void listBox1_MouseHover(object sender, EventArgs e)
        {
            this.OnMouseHover(e);
        }

        private void listBox1_MouseLeave(object sender, EventArgs e)
        {
            this.OnMouseLeave(e);
        }

        private void listBox1_MouseMove(object sender, MouseEventArgs e)
        {
            this.OnMouseMove(e);
        }

        private void listBox1_MouseUp(object sender, MouseEventArgs e)
        {
            this.OnMouseUp(e);
        }

        private void listBox1_KeyDown(object sender, KeyEventArgs e)
        {
            this.OnKeyDown(e);
        }

        private void listBox1_KeyPress(object sender, KeyPressEventArgs e)
        {
            this.OnKeyPress(e);
        }

        private void listBox1_KeyUp(object sender, KeyEventArgs e)
        {
            this.OnKeyUp(e);
        }

    }
}
