using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using C1.Silverlight.Data;

namespace CollectionViewFilter
{
    public class ViewFilter
    {
        // ** fields
        System.ComponentModel.ICollectionView _view;
        string _filterExpression;
        DataTable _dt;

        // ** ctor
        public ViewFilter(System.ComponentModel.ICollectionView view)
        {
            _view = view;
        }

        // ** object model
        public string FilterExpression
        {
            get { return _filterExpression; }
            set
            {
                _filterExpression = value;
                _view.Filter = null;
                UpdateFilter();
                if (!string.IsNullOrEmpty(_filterExpression.Trim()))
                {
                    _view.Filter = FilterPredicate;
                }
            }
        }

        // ** implementation
        bool FilterPredicate(object obj)
        {
            // populate the row
            var row = _dt.Rows[0];
            foreach (var pi in obj.GetType().GetProperties())
            {
                row[pi.Name] = pi.GetValue(obj, null);
            }

            // compute the expression
            try
            {
                return (bool)row["_filter"];
            }
            catch
            {
                // syntax error
                var msg = string.Format(
                    "Error evaluating expression [{0}].\r\n\r\n" +
                    "Please use complete expressions and remember\r\n" +
                    "to enclose strings in single quotes.\r\n\r\n" +
                    "For example \" name > 's' \" or \" name like 's*' \".", _filterExpression);
                System.Windows.MessageBox.Show(msg, "Syntax Error", System.Windows.MessageBoxButton.OK);
                _view.Filter = null;
                return true;
            }
        }
        void UpdateFilter()
        {
            if (_view.CurrentItem == null)
            {
                // current item might be null, if previous filter returned an empty view
                _view.MoveCurrentToFirst();
            }
            if (_view.CurrentItem != null && !string.IsNullOrEmpty(_filterExpression))
            {
                // build/rebuild data table
                _dt = null;
                var dt = new DataTable();
                foreach (var pi in _view.CurrentItem.GetType().GetProperties())
                {
                    dt.Columns.Add(pi.Name, pi.PropertyType);
                }

                // add calculated column
                dt.Columns.Add("_filter", typeof(bool), _filterExpression);

                // create a single row for evaluating expressions
                if (dt.Rows.Count == 0)
                {
                    dt.Rows.Add(dt.NewRow());
                }

                // done, save table
                _dt = dt;
            }
        }
    }
}
