text: ﻿using Nitra.Internal;
  using Nitra.ProjectSystem;
  
  using Nemerle;
  using Nemerle.Collections;
  using Nemerle.Text;
  using Nemerle.Utility;
  
  using System;
  using System.Collections.Generic;
  using System.Linq;
  
  namespace Nitra.Declarations
  {
    public interface IAstOption[+T] : IAst
      where T : IAst
    {
      HasValue : bool  { get; }
      Value    : T     { get; }
    }
  
    public class AstOption[T] : AstBase, IAstOption[T]
      where T : IAst
    {
      protected _value     : T;
  
      public HasValue    : bool  { get; }
      public Value       : T
      {
        get
        {
          unless (HasValue)
            throw InvalidOperationException("Value not set");
          _value;
        }
      }
  
      public this(loc : ILocated)
      {
        this(loc.Location)
      }
  
      public this(loc : Location)
      {
        Source = loc.Source;
        Span   = loc.Span;
      }
  
      public this(loc : ILocated, value : T)
      {
        this(loc.Location, value)
      }
  
      public this(loc : Location, value : T)
      {
        this(loc);
        _value  = value;
        def valueLoc = value.Location;
        when (valueLoc.Source : object == Source)
          Span += valueLoc.Span;
        HasValue = true;
      }
  
      public override EvalProperties(context : DependentPropertyEvalContext) : void
      {
        when (HasValue)
          _value.EvalProperties(context);
      }
  
      public override ToXaml() : string
      {
        if (HasValue)
          _value.ToString()
        else
          "<Span Foreground = 'gray'>None</Span>"
      }
  
      public override Accept(visitor : IAstVisitor) : void
      {
        when (HasValue)
          match (_value)
          {
            | x is Reference => visitor.Visit(x);
            | x is Name      => visitor.Visit(x);
            | x              => visitor.Visit(x);
          }
      }
    }
  
    public class AmbiguousAstOption[T] : IAstOption[T], IAmbiguousAst
      where T : IAst
    {
      public this(ambiguities : array[IAstOption[T]])
      {
        Ambiguities = ambiguities
      }
  
      public Ambiguities       : array[IAstOption[T]] { get; }
      public Location          : Location             { get { Ambiguities[0].Location } }
      public Source            : SourceSnapshot       { get { Ambiguities[0].Source } }
      public Span              : NSpan                { get { Ambiguities[0].Span } }
      public IsAmbiguous       : bool                 { get { true } }
      public IsMissing         : bool                 { get { false } }
      public HasValue          : bool                 { get { Ambiguities[0].HasValue } }
      public Value             : T                    { get { Ambiguities[0].Value } }
  
      private AmbiguitiesImpl : array[IAst] implements IAmbiguousAst.Ambiguities { get { Ambiguities :> array[IAst] } }
  
      public EvalProperties(context : DependentPropertyEvalContext) : void
      {
        AstUtils.EvalAmbiguitiesProperties(context, this)
      }
  
      public PropertiesEvalState : int
      {
        get { Ambiguities[0].PropertiesEvalState }
      }
  
      public ResetProperties() : void
      {
        AstUtils.ResetAmbiguitiesProperties(this)
      }
  
      public IsAllPropertiesEvaluated : bool
      {
        get { Ambiguities[0].IsAllPropertiesEvaluated }
      }
  
      public ToXaml() : string { "AmbiguousOption Count: " + Ambiguities.Length }
  
      public Accept(visitor : IAstVisitor) : void
      {
        foreach (item in Ambiguities)
          item.Accept(visitor);
      }
    }
  }
  