\import Data.List (List)
\import Data.Or
\import Logic
\import Logic.Meta
\import Paths
\import Paths.Meta
\import Data.Fin
\import Data.SubList
\import Logic.Rewriting.TRS.HRS
\import Logic.Rewriting.TRS.Substitutions

\func ModularMetaContext {env : FSignature} {n : Nat} (meta-contexts : Fin n -> MetaContext Sort) : MetaContext Sort
\cowith
  | metaname s => \Sigma (i : Fin n) (metaname {meta-contexts i} s)
  | m-domain m => m-domain {meta-contexts m.1} m.2
  \where {
    \func upgrade-metavariables
      {env : FSignature} {context : List Sort} {s : Sort} {n : Nat}
      {index : Fin n}
      (meta-contexts : Fin n -> MetaContext Sort)
      (A : Term env context s (meta-contexts index))
      : Term env context s (ModularMetaContext meta-contexts)
    \elim A
      | var index p => var index p
      | metavar m arguments => metavar (index, m) (\lam i => upgrade-metavariables meta-contexts (arguments i))
      | func f arguments => func f (\lam i => upgrade-metavariables meta-contexts (arguments i))
  }

\func PointedModularMetaContext {env : FSignature} {n : Nat} (point : Sort) (context-for-point : List Sort)
                                (meta-contexts : Fin n -> MetaContext Sort) : MetaContext Sort
\cowith
  | metaname s => (s = point) `Or` metaname {ModularMetaContext meta-contexts} s
  | m-domain m => \case \elim m \with {
    | inl eq => context-for-point
    | inr m => m-domain {ModularMetaContext meta-contexts} m
  }
  \where {
    \func upgrade-metavariables
      {env : FSignature} {context : List Sort} {s : Sort}
      (point : Sort)
      (pointed-context : List Sort)
      {index : Index pointed-context}
      (metas : \Pi (Index pointed-context) -> MetaContext Sort)
      (A : Term env context s (metas index))
      : Term env context s (PointedModularMetaContext point pointed-context metas)
    \elim A
      | var index p => var index p
      | metavar m arguments => metavar (inr (index, m)) (\lam i => upgrade-metavariables point pointed-context metas (arguments i))
      | func f arguments => func f (\lam i => upgrade-metavariables point pointed-context metas (arguments i))
  }

\func SingularMetaContext {env : FSignature} (point : Sort) (context : List Sort)
  : MetaContext Sort \cowith
  | metaname s => s = point
  | m-domain eq => context

\func EmptyMetaContext {env : FSignature} : MetaContext Sort \cowith
  | metaname m => Empty
  | m-domain e => contradiction

\func PureTerm (env : FSignature) (context : List Sort) (s : Sort) : \Type => Term env context s EmptyMetaContext

\lemma apply-modularity {env : FSignature} {context subst-context pattern-context : List Sort} {s : Sort} {mc : MetaContext Sort} {n : Nat} {index : Fin n}
                        (producer : Fin n -> MetaContext Sort)
                        (substitutions : \Pi (i : Fin n) -> MetaSubstitution env subst-context (producer i) mc)
                        (sublist : SubList subst-context context)
                        (pat-sublist : SubList pattern-context context)
                        (t : Term env pattern-context s (producer index)) :
  MetaSubstitution.apply (weakening t pat-sublist) sublist (substitutions index) = MetaSubstitution.apply (weakening (ModularMetaContext.upgrade-metavariables producer t) pat-sublist) sublist (\lam m => substitutions m.1 m.2) \elim t
  | var index1 p => idp
  | metavar m arguments => pmap (\lam e => Substitution.apply (substitutions index m) (extend-substitution-left sublist e)) (ext (\lam i => apply-modularity producer substitutions sublist pat-sublist (arguments i)))
  | func f arguments => Term.fext (\lam i => apply-modularity producer substitutions (SubList.extend-right-single sublist) (SubList.extend-right-both pat-sublist) (arguments i))