using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using ZipBrowser.SR;

namespace ZipBrowser
{
    public partial class MainPage : UserControl
    {
        //----------------------------------------------------------------------------------
        #region ** fields

        const string _imgExtensions = 
            ".png.jpg.bmp";

        const string _txtExtensions =
            ".sln.csproj.vbproj.cs.vb.txt.licx.resx.xaml.xml" +
            ".config.settings.svc.svcinfo.svcmap.wsdl.disco" +
            ".html.htm.js.aspx.ashx.asmx" +
            ".xsc.xsd.xss";

        string _zipUrl;
        string _itemPath;
        ZipItem _root;

        #endregion

        //----------------------------------------------------------------------------------
        #region ** ctor

        public MainPage()
        {
            InitializeComponent();
        }

        #endregion

        //----------------------------------------------------------------------------------
        #region ** get service (on localhost or on real server)

        // see http://forums.silverlight.net/forums/t/19021.aspx
        public static ZipBrowserServiceSoapClient GetServiceClient()
        {
            // this URL will work both in dev and after deploy.
            Uri address = new Uri(Application.Current.Host.Source, "../ZipBrowserService.asmx");
            var b = new System.ServiceModel.BasicHttpBinding();
            b.MaxBufferSize = 500000;
            b.MaxReceivedMessageSize = 500000;
            var a = new System.ServiceModel.EndpointAddress(address.AbsolutePath);
            return new ZipBrowserServiceSoapClient(b, a);
        }

        #endregion

        //----------------------------------------------------------------------------------
        #region ** load zip contents, show it on treeview

        void _btnLoad_Click(object sender, RoutedEventArgs e)
        {
            Load();
        }
        void _urlCombo_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                Load();
            }
        }
        void _urlCombo_SelectedItemChanged(object sender, C1.Silverlight.PropertyChangedEventArgs<object> e)
        {
            Load();
        }
        void Load()
        {
            if (_urlCombo != null && _urlCombo.Text != _zipUrl)
            {
                var url = _urlCombo.Text;
                ShowMessage("Loading {0}...", System.IO.Path.GetFileName(url));
                var svc = GetServiceClient();
                svc.GetContentCompleted += svc_GetContentCompleted;
                svc.GetContentAsync(url, url);
            }
        }
        void svc_GetContentCompleted(object sender, SR.GetContentCompletedEventArgs e)
        {
            _rtb.Text = string.Empty;
            if (e.Error != null)
            {
                ShowError(e.Error);
            } 
            else if (!e.Cancelled)
            {
                // save results
                _zipUrl = (string)e.UserState;
                _root = e.Result;

                // show on tree
                _tree.ItemsSource = new object[] { _root }; //.Items;

                // expand root node
                _tree.UpdateLayout();
                var tvi = _tree.ItemContainerGenerator.ContainerFromIndex(0) as C1.Silverlight.C1TreeViewItem;
                if (tvi != null)
                {
                    tvi.IsExpanded = true;
                }
            }
        }

        #endregion

        //----------------------------------------------------------------------------------
        #region ** show selected item on preview pane

        void treeView1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // get the selected ZipItem
            if (_tree.SelectedItem != null)
            {
                var zi = _tree.SelectedItem.DataContext as ZipItem;
                if (zi != null && zi.Items.Count == 0)
                {
                    // show image or text (or ignore the file)
                    var ext = System.IO.Path.GetExtension(zi.Path);
                    if (_imgExtensions.IndexOf(ext, StringComparison.OrdinalIgnoreCase) > -1)
                    {
                        ShowImage(zi);
                    }
                    else if (_txtExtensions.IndexOf(ext, StringComparison.OrdinalIgnoreCase) > -1)
                    {
                        ShowText(zi);
                    }
                    else
                    {
                        // we don't show this type of file...
                    }
                }
            }
        }

        // show message while loading images/text
        void ShowMessage(string format, params object[] args)
        {
            _img.Visibility = System.Windows.Visibility.Collapsed;
            _rtb.Text = string.Format(format, args);
        }
        void ShowError(Exception x)
        {
            string msg = x.Message;
            while (x.InnerException != null)
            {
                msg += "\r\nInner Exception:\r\n" + x.InnerException.Message;
                x = x.InnerException;   
            }
            ShowMessage("** Error:\r\n\r\n{0}", msg);
        }

        #endregion

        //----------------------------------------------------------------------------------
        #region ** show images from zip file

        void ShowImage(ZipItem item)
        {
            ShowMessage("Loading {0}...", System.IO.Path.GetFileName(item.Path));
            var svc = GetServiceClient();
            svc.GetEntryBytesCompleted += svc_GetEntryBytesCompleted;
            svc.GetEntryBytesAsync(_zipUrl, item.Path);
        }
        void svc_GetEntryBytesCompleted(object sender, GetEntryBytesCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                ShowError(e.Error);
            } 
            else if (!e.Cancelled && e.Result.Length > 0)
            {
                _rtb.Text = string.Empty;
                var bytes = e.Result;
                var bmp = new System.Windows.Media.Imaging.BitmapImage();
                bmp.SetSource(new MemoryStream(bytes));
                _img.Source = bmp;
                _img.Visibility = System.Windows.Visibility.Visible;
            }
        }

        #endregion

        //----------------------------------------------------------------------------------
        #region ** show text from zip file

        void ShowText(ZipItem item)
        {
            ShowMessage("Loading {0}...", System.IO.Path.GetFileName(item.Path));
            _itemPath = item.Path;
            var svc = GetServiceClient();
            svc.GetEntryTextCompleted += svc_GetEntryTextCompleted;
            svc.GetEntryTextAsync(_zipUrl, item.Path);
        }
        void svc_GetEntryTextCompleted(object sender, GetEntryTextCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                ShowError(e.Error);
            } 
            else if (!e.Cancelled)
            {
                _rtb.SyntaxType = GetSyntaxType(_itemPath);
                _rtb.Text = e.Result;
            }
        }
        static SyntaxType GetSyntaxType(string fileName)
        {
            var ext = System.IO.Path.GetExtension(fileName).ToLower();
            switch (ext)
            {
                case "":
                case ".txt":
                case ".sln":
                    return SyntaxType.PlainText;
                case ".cs":
                case ".js":
                    return SyntaxType.CS;
                case ".vb":
                    return SyntaxType.VB;
            }
            return SyntaxType.Xml;
        }

        #endregion
    }

    public class ZipItemBrushConverter : System.Windows.Data.IValueConverter
    {
        static Brush _brFolderBkg = new SolidColorBrush(Color.FromArgb(0xc0, 0xff, 0xe3, 0x44));
        static Brush _brFolderBdr = new SolidColorBrush(Colors.Black);

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var zi = value as ZipItem;
            if ((string)parameter == "bkg")
            {
                return zi.Items.Count > 0 ? _brFolderBkg : null;
            }
            else if ((string)parameter == "bdr")
            {
                return zi.Items.Count > 0 ? _brFolderBdr : null;
            }
            else if ((string)parameter == "fw")
            {
                return zi.Items.Count > 0 ? FontWeights.Bold : FontWeights.Normal;
            }
            throw new Exception("invalid argument, expecting 'bkg', 'bdr', or 'fw'.");
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
