/*
 *    Debrief - the Open Source Maritime Analysis Application
 *    http://debrief.info
 *
 *    (C) 2000-2014, PlanetMayo Ltd
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the Eclipse Public License v1.0
 *    (http://www.eclipse.org/legal/epl-v10.html)
 *
 *    This library 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. 
 */
package org.mwc.cmap.NarrativeViewer;

import java.util.Iterator;
import java.util.LinkedList;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.nebula.jface.gridviewer.GridColumnLayout;
import org.eclipse.nebula.jface.gridviewer.GridTableViewer;
import org.eclipse.nebula.widgets.grid.GridColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.dialogs.PatternFilter;
import org.mwc.cmap.NarrativeViewer.actions.NarrativeViewerActions;
import org.mwc.cmap.NarrativeViewer.filter.ui.FilterDialog;
import org.mwc.cmap.NarrativeViewer.model.TimeFormatter;

import MWC.GenericData.HiResDate;
import MWC.TacticalData.IRollingNarrativeProvider;
import MWC.TacticalData.NarrativeEntry;

public class NarrativeViewer
{

  final NarrativeViewerModel myModel;
  private NarrativeViewerActions myActions;

  final GridTableViewer viewer;
  private FilteredGrid filterGrid;

  public NarrativeViewer(final Composite parent,
      final IPreferenceStore preferenceStore)
  {
    GridColumnLayout layout = new GridColumnLayout();

    filterGrid =
        new FilteredGrid(parent, SWT.V_SCROLL | SWT.BORDER | SWT.MULTI,
            new PatternFilter()
            {

              @Override
              public boolean isElementVisible(Viewer viewer, Object element)
              {
                return isLeafMatch(viewer, element);
              }

              @Override
              protected boolean isLeafMatch(Viewer viewer, Object element)
              {

                AbstractColumn[] allColumns = myModel.getAllColumns();
                for (AbstractColumn abstractColumn : allColumns)
                {
                  if (abstractColumn.isVisible())
                  {
                    Object property =
                        abstractColumn.getProperty((NarrativeEntry) element);
                    String text = property != null ? property.toString() : null;
                    if (text != null && wordMatches(text))
                    {
                      return true;
                    }
                  }
                }

                return false;
              }

            }, true);
    filterGrid.getGridComposite().setLayout(layout);
    viewer = filterGrid.getViewer();
    viewer.getGrid().setHeaderVisible(true);
    viewer.getGrid().setLinesVisible(true);

    viewer.setAutoPreferredHeight(true);

    myModel = new NarrativeViewerModel(preferenceStore);

    myModel.createTable(this, layout);

  }

  public GridTableViewer getViewer()
  {
    return viewer;
  }

  public Composite getControl()
  {
    return filterGrid;
  }

  FilteredGrid getFilterGrid()
  {
    return filterGrid;
  }

  public NarrativeViewerActions getViewerActions()
  {
    if (myActions == null)
    {
      myActions = new NarrativeViewerActions(this);
    }
    return myActions;
  }

  public void showFilterDialog(final Column column)
  {
    if (!myModel.hasInput())
    {
      return;
    }

    final ColumnFilter filter = column.getFilter();
    if (filter == null)
    {
      return;
    }

    final FilterDialog dialog =
        new FilterDialog(viewer.getGrid().getShell(), myModel.getInput(),
            column);

    if (Dialog.OK == dialog.open())
    {
      dialog.commitFilterChanges();
      refresh();
    }
  }

  public void setInput(final IRollingNarrativeProvider entryWrapper)
  {
    myModel.setInput(entryWrapper);
    Display.getDefault().asyncExec(new Runnable()
    {

      @Override
      public void run()
      {
        refresh();

      }
    });
  }

  public void setTimeFormatter(final TimeFormatter timeFormatter)
  {
    myModel.setTimeFormatter(timeFormatter);
    viewer.refresh();
  }

  public void refresh()
  {
    // check we're not closing
    if (!viewer.getControl().isDisposed()
        && viewer.getContentProvider() != null)
    {
      viewer.setInput(new Object());
    }
  }

  private void calculateGridRawHeight()
  {
    ISelection selection = viewer.getSelection();
    viewer.getGrid().setRedraw(false);
    viewer.setInput(new Object());
    viewer.setSelection(selection);
    viewer.getGrid().setRedraw(true);
  }

  public boolean isWrappingEntries()
  {
    return myModel.isWrappingEntries();
  }

  public void setWrappingEntries(final boolean shouldWrap)
  {
    if (myModel.setWrappingEntries(shouldWrap))
    {
      GridColumn[] columns = getViewer().getGrid().getColumns();
      for (GridColumn gridColumn : columns)
      {
        gridColumn.setWordWrap(shouldWrap);
      }
      calculateGridRawHeight();
    }
  }

  /**
   * the controlling time has updated
   * 
   * @param dtg
   *          the selected dtg
   */
  public void setDTG(final HiResDate dtg)
  {
    // find the table entry immediately after or on this DTG
    NarrativeEntry entry = null;

    // retrieve the list of visible rows
    final LinkedList<NarrativeEntry> visEntries = myModel.myVisibleRows;

    // step through them
    for (final Iterator<NarrativeEntry> entryIterator = visEntries.iterator(); entryIterator
        .hasNext();)
    {
      final NarrativeEntry narrativeEntry =
          (NarrativeEntry) entryIterator.next();

      // get the date
      final HiResDate dt = narrativeEntry.getDTG();

      // is this what we're looking for?
      if (dt.greaterThanOrEqualTo(dtg))
      {
        entry = narrativeEntry;
        break;
      }

    }

    // ok, try to select this entry
    if (entry != null)
    {
      setEntry(entry);
    }

  }

  /**
   * the controlling time has updated
   * 
   * @param dtg
   *          the selected dtg
   */
  public void setEntry(final NarrativeEntry entry)
  {
    // select this item
    viewer.setSelection(new StructuredSelection(entry));

    // make sure the new item is visible
    viewer.reveal(entry);
  }

  public NarrativeViewerModel getModel()
  {
    return myModel;
  }

}

@@ -629,16 +629,49 @@
 edList;%0D
+%0Aimport java.util.regex.Pattern;%0D
 %0A%0D%0Aimpor
@@ -2354,32 +2354,143 @@
              %7B%0D%0A
+                Pattern pattern = Pattern.compile(getFilterGrid().getFilterString(), Pattern.CASE_INSENSITIVE);
 %0D%0A              
@@ -2948,25 +2948,36 @@
  && 
-wordM
+pattern.m
 atche
-s
+r
 (text)
+.find()
 )%0D%0A 

use custom pattern