/*****************************************************************************
**
**    Square.cs
**
*****************************************************************************/
using System;
 
class Square
    {
/*    -----------------------------------------------------------------------
    VARIABLES
    -----------------------------------------------------------------------    */
    protected readonly int    _index = -1;
 
    protected int            _iCandidates = -1;
    protected int            _iValue = -1;
    protected BitSet        _candidates = new BitSet();
/*    -----------------------------------------------------------------------
    CONSTRUCTOR
    -----------------------------------------------------------------------    */
    ///
    ///    <summary>
    ///    Constructor for the square class
    ///    </summary>
    ///    <param name="index">Index of the square</param>
    /// <exception cref="IndexOutOfRangeException">
    /// Raised if the iHouse is not valid.
    /// </exception>    
    ///    <remarks>
    ///    Since squares should never be moved around on the grid, set the iHouse
    ///    once via the CTOR, then leave it alone.
    ///    </remarks>
    ///    
    public
    Square(int index)
        {
        if (!Grid.IsValidIndex(index))
            throw new IndexOutOfRangeException();
 
        _index = index;
 
        Reset();
        }    /* end of Square::Square() */
/*    -----------------------------------------------------------------------
    METHODS
    -----------------------------------------------------------------------    */
    ///
    ///    <summary>
    ///    Clears a candidate for the square
    ///    </summary>
    ///    <returns>TRUE if candidate eliminated, FALSE otherwise</returns>
    ///    <param name="iValue">Value to eliminate</param>
    /// <exception cref="ValueOutOfRangeException">
    /// Raised if the value is outside the range of Grid.ValueMin to Grid.ValueMax
    /// </exception>
    /// <exception cref="UnsolvableSquareException">
    /// Raised if the square ends up with no viable candidates
    /// </exception>
    ///
    public bool
    ClearCandidate(int iValue)
        {
        if (!Grid.IsValidValue( iValue ))
            throw new ArgumentOutOfRangeException( "iValue" );
 
        if (IsEmpty && _candidates.Test( iValue ))
            {
            _iCandidates--;
            _candidates.Clear(iValue);
            if (_candidates.Empty)
                throw new UnsolvableSquareException(_index);
 
            return true;
            }
 
        return false;
        }    /* end of Square::ClearCandidate() */
    ///
    ///    <summary>
    ///    Clears all candidates for the square
    ///    </summary>
    ///
    public void
    ClearAllCandidates()
        {
        _iCandidates = 0;
        _candidates.ClearAll();
        }    /* end of Square::ClearAllCandidates() */
    ///
    ///    <summary>
    ///    Clears the square, setting it to it's initial state
    ///    </summary>
    ///
    public void
    Reset()
        {
        _iCandidates = (Grid.ValueMax - Grid.ValueMin) + 1;
        _iValue    = Grid.ValueNone;
        _candidates.SetRange( Grid.ValueMin, Grid.ValueMax );
        }    /* end of Square::Reset() */
    ///
    ///    <summary>
    ///    Clears a candidate for the square
    ///    </summary>
    ///    <returns>TRUE if candidate eliminated, FALSE otherwise</returns>
    ///    <param name="iValue">Value to eliminate</param>
    /// <exception cref="ValueOutOfRangeException">
    /// Raised if the value is outside the range of Grid.ValueMin to Grid.ValueMax
    /// </exception>
    /// <exception cref="UnsolvableSquareException">
    /// Raised if the square ends up with no viable candidates
    /// </exception>
    ///
    public bool
    SetCandidate(int iValue)
        {
        if (!Grid.IsValidValue( iValue ))
            throw new ArgumentOutOfRangeException( "iValue" );
 
        if (IsEmpty && !_candidates.Test( iValue ))
            {
            _iCandidates++;
            _candidates.Set(iValue);
            return true;
            }
 
        return false;
        }    /* end of Square::SetCandidate() */
/*    -----------------------------------------------------------------------
    PROPERTIES
    -----------------------------------------------------------------------    */
    ///
    ///    <summary>
    ///    Returns a bitset representing the valid candidates for this square
    ///    </summary>
    ///    <returns>Bitset by value</returns>
    ///
    public BitSet
    Candidates
        {
        get
            { return _candidates; }
        }    /* end of Square::Candidates() */
    ///
    ///    <summary>
    ///    Returns a count of the valid candidates for this square
    ///    </summary>
    ///    <returns>Count</returns>
    ///
    public int
    CandidateCount
        {
        get
            { return _iCandidates; }
        }    /* end of Square::CandidateCount() */
    ///
    ///    <summary>
    ///    The position of the square on the puzzle grid.
    ///    </summary>
    ///    <returns>Index of the square</returns>
    ///
    public int
    Index
        {
        get
            { return _index; }
        }    /* end of Square::Index() */
    ///
    ///    <summary>
    ///    Evaluates if a square is empty (blank)
    ///    </summary>
    ///    <returns>TRUE if square is empty</returns>
    ///    
    public bool
    IsEmpty
        {
        get
            { return (_iValue == Grid.ValueNone); }
        }    /* end of Square::IsEmpty() */
    ///
    ///    <summary>
    ///    The square's value
    ///    </summary>
    ///    <returns>Value, or ValueNone if empty</returns>
    ///
    public int
    Value
        {
        get
            { return _iValue; }
        set
            {
            if (!(value == Grid.ValueNone || Grid.IsValidValue(value)))
                throw new ValueOutOfRangeException();
 
            _iValue = value;
            if (value == Grid.ValueNone)
                Reset();
            else if (_candidates.Test(_iValue))
                {
                _iCandidates = 0;
                _candidates.ClearAll();
                }
            else
                throw new IllegalValueException(_index, _iValue);
            }
        }    /* end of Square::Value() */
    };
/*****************************************************************************
**
**    End of Square.cs
**
*****************************************************************************/