import Graphics.UI.Gtk
import Data.Char
import Data.List
import Data.Maybe

data RowInfo = RowInfo { rowString :: String, rowCase :: Maybe Bool }

mkCase Nothing str = str
mkCase (Just False) str = map toLower str
mkCase (Just True) str = map toUpper str

advCase Nothing = Just False
advCase (Just False) = Just True
advCase (Just True) = Nothing

main :: IO ()
main = do
  unsafeInitGUIForThreadedRTS
  win <- windowNew
  win `on` objectDestroy $ mainQuit

  content <- readFile "ListText.hs"

  model <- listStoreNew (map (\r -> RowInfo r Nothing) (lines content))
  view <- treeViewNewWithModel model

  -- add a column showing the index
  col <- treeViewColumnNew
  treeViewAppendColumn view col

  cell <- cellRendererTextNew
  cellLayoutPackStart col cell True
  cellLayoutSetAttributeFunc col cell model $ \(TreeIter _ n _ _) ->
    set cell [cellText := show n]
  set col [treeViewColumnTitle := "line",
           treeViewColumnReorderable := True ]

  -- add a column showing the line in the file
  col <- treeViewColumnNew
  treeViewAppendColumn view col
  set col [treeViewColumnTitle := "line in file",
           treeViewColumnReorderable := True ]

  cell <- cellRendererTextNew
  cellLayoutPackStart col cell True
  cellLayoutSetAttributes col cell model $
    \row -> [cellText := mkCase (rowCase row) (rowString row)]

  -- add a column showing if it is forced to a specific case
  col <- treeViewColumnNew
  treeViewAppendColumn view col
  set col [treeViewColumnTitle := "case",
           treeViewColumnReorderable := True ]

  cell <- cellRendererToggleNew
  cellLayoutPackStart col cell True
  cellLayoutSetAttributes col cell model $
    \row -> [cellToggleActive := fromMaybe False (rowCase row),
             cellToggleInconsistent := rowCase row==Nothing]
  cell `on` cellToggled $ \tpStr -> do
    let [i] = stringToTreePath tpStr
    row@RowInfo { rowCase = c } <- listStoreGetValue model i
    listStoreSetValue model i row { rowCase = advCase c }

  -- to annoy the user: don't allow any columns to be dropped at the far right
  treeViewSetColumnDragFunction view $ Just $ \_ rCol _ -> do
    return (rCol /= Nothing)

  treeViewSetSearchEqualFunc view $ Just $ \str (TreeIter _ n _ _) -> do
    row <- listStoreGetValue model (fromIntegral n)
    return (map toLower str `isPrefixOf` map toLower (filter isAlphaNum (rowString row)))

  swin <- scrolledWindowNew Nothing Nothing
  set swin [ containerChild := view ]
  set win [ containerChild := swin ]
  widgetShowAll win
  mainGUI
