{-# LANGUAGE FlexibleContexts #-}
-----------------------------------------------------------------------------
-- Copyright 2019, Advise-Me project team. This file is distributed under 
-- the terms of the Apache License 2.0. For more information, see the files
-- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer  :  bastiaan.heeren@ou.nl
-- Stability   :  provisional
-- Portability :  portable (depends on ghc)
--
-- This module exposes a set of functions for manipulating and parsing expressions using strategies.
-- 
-----------------------------------------------------------------------------

module Recognize.Strategy.Applications
   ( normalize, simplify, pSolveLinear
   ) where

import Control.Arrow
import Data.Maybe
import Domain.Math.Data.Relation
import Domain.Math.Expr
import Ideas.Common.Library hiding (simplify)
import Recognize.Data.Attribute
import Recognize.Data.Math
import Recognize.Data.Diagnosis
import Recognize.Parsing.Parse
import Recognize.Strategy.Derivation
import Recognize.Strategy.Exercises
import Recognize.Strategy.Recognizer
import Recognize.Expr.Normalform
import Util.Cache

-- | Normalizes (commutativity, associativity, distributivity, etc) an expression. Returns a product of a normalized expression and applied rewrites
normalize :: Expr -> (Expr, [Attribute])
normalize = cached "normalize" $ \e ->
   first nfComAssoc $ fromMaybe (e,[]) $ deriveExprSteps normalizeExercise e

-- | Simplifies an expression. Returns a product of the simplified expression and applied rewrites.
simplify :: Expr -> (Expr, [Attribute])
simplify = cached "simplify" $ \e ->
   first nfComAssoc $ fromMaybe (e,[]) $ deriveExprSteps simplifyExercise e

-- | Given an exercise, find a default derivation for an expression. Returning the derived expression and applied rewrites.
deriveExprSteps :: (Show e, ToAttribute e) => Exercise e -> e -> Maybe (e,[Attribute])
deriveExprSteps ex e = do
  deriv <- defaultDerivation ex e
  attrs <- fromDerivation $ updateSteps (\_ s _ -> fst s) deriv
  let term = lastTerm deriv
  se <- fromContext term
  return (se, attrs)

-- | Parses expressions that solve a linear equation. Returns the steps (containing rewrites) taken.
pSolveLinear :: (ParseLog m, Parse m Math, Relational f) => Maybe (f Expr, Math) -> m (Relation Expr, [Step])
pSolveLinear mfe = pExercise recognizerExercise mrel
  where
    mrel = fmap (first (\fe -> leftHandSide fe .==. rightHandSide fe)) mfe