#region PDFsharp - A .NET library for processing PDF
//
// Authors:
//   Stefan Lange (mailto:Stefan.Lange@pdfsharp.com)
//
// Copyright (c) 2005-2007 empira Software GmbH, Cologne (Germany)
//
// http://www.pdfsharp.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.
#endregion

using System;
using System.Diagnostics;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Text;

namespace PdfSharp.Pdf.Content.Objects
{
  /// <summary>
  /// Base class for all PDF content stream objects.
  /// </summary>
  public class CObject : ICloneable
  {
    /// <summary>
    /// Initializes a new instance of the <see cref="CObject"/> class.
    /// </summary>
    public CObject() 
    {
    }

    /// <summary>
    /// Creates a new object that is a copy of the current instance.
    /// </summary>
    object ICloneable.Clone()
    {
      return Copy();
    }

    /// <summary>
    /// Creates a new object that is a copy of the current instance.
    /// </summary>
    public CObject Clone()
    {
      return (CObject)Copy();
    }

    /// <summary>
    /// Implements the copy mechanism. Must be overridden in derived classes.
    /// </summary>
    protected virtual CObject Copy()
    {
      return (CObject)MemberwiseClone();
    }
  }

  /// <summary>
  /// Represents a comment in a PDF content stream.
  /// </summary>
  [DebuggerDisplay("({Text})")]
  public class CComment : CObject
  {
    /// <summary>
    /// Creates a new object that is a copy of the current instance.
    /// </summary>
    public new CComment Clone()
    {
      return (CComment)Copy();
    }

    /// <summary>
    /// Implements the copy mechanism of this class.
    /// </summary>
    protected override CObject Copy()
    {
      CObject obj = base.Copy();
      return obj;
    }

    /// <summary>
    /// Gets or sets the comment text.
    /// </summary>
    public string Text
    {
      get { return this.text; }
      set { this.text = value; }
    }
    string text;

    public override string ToString()
    {
      return "% " + this.text;
    }
  }

  /// <summary>
  /// Represents a sequence of objects in a PDF content stream.
  /// </summary>
  [DebuggerDisplay("(count={Count})")]
  public class CSequence : CObject, IList, ICollection, IEnumerable
  {
    ArrayList items = new ArrayList();

    /// <summary>
    /// Creates a new object that is a copy of the current instance.
    /// </summary>
    public new CSequence Clone()
    {
      return (CSequence)Copy();
    }

    /// <summary>
    /// Implements the copy mechanism of this class.
    /// </summary>
    protected override CObject Copy()
    {
      CObject obj = base.Copy();
      this.items = (ArrayList)this.items.Clone();
      for (int idx = 0; idx < this.items.Count; idx++)
      {
        this.items[idx] = ((CObject)(this.items[idx])).Clone();
      }
      return obj;
    }

    /// <summary>
    /// Adds the specified sequence.
    /// </summary>
    /// <param name="sequence">The sequence.</param>
    public void Add(CSequence sequence)
    {
      int count = sequence.Count;
      for (int idx = 0; idx < count; idx++)
        this.items.Add(sequence[idx]);
    }


    #region IList Members

    /// <summary>
    /// Adds an item to the <see cref="T:System.Collections.IList"></see>.
    /// </summary>
    /// <param name="value">The <see cref="T:System.Object"></see> to add to the <see cref="T:System.Collections.IList"></see>.</param>
    /// <returns>
    /// The position into which the new element was inserted.
    /// </returns>
    /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.IList"></see> is read-only.-or- The <see cref="T:System.Collections.IList"></see> has a fixed size. </exception>
    int IList.Add(object value)
    {
      return this.items.Add(value);
    }

    public int Add(CObject value)
    {
      return this.items.Add(value);
    }

    public void Clear()
    {
      this.items.Clear();
    }

    bool IList.Contains(object value)
    {
      return this.items.Contains(value);
    }

    public bool Contains(CObject value)
    {
      return this.items.Contains(value);
    }

    int IList.IndexOf(object value)
    {
      return this.items.IndexOf(value);
    }

    public int IndexOf(CObject value)
    {
      return this.items.IndexOf(value);
    }

    void IList.Insert(int index, object value)
    {
      this.items.Insert(index, value);
    }

    public void Insert(int index, CObject value)
    {
      this.items.Insert(index, value);
    }

    public bool IsFixedSize
    {
      get { return this.items.IsFixedSize; }
    }

    public bool IsReadOnly
    {
      get { return this.items.IsReadOnly; }
    }

    void IList.Remove(object value)
    {
      this.items.Remove(value);
    }

    public void Remove(CObject value)
    {
      this.items.Remove(value);
    }

    public void RemoveAt(int index)
    {
      this.items.RemoveAt(index);
    }

    object IList.this[int index]
    {
      get { return this.items[index]; }
      set { this.items[index] = value; }
    }

    public CObject this[int index]
    {
      get { return (CObject)this.items[index]; }
      set { this.items[index] = value; }
    }
    #endregion

    #region ICollection Members

    public void CopyTo(Array array, int index)
    {
      this.items.CopyTo(array, index);
    }

    public int Count
    {
      get { return this.items.Count; }
    }

    public bool IsSynchronized
    {
      get { return this.items.IsSynchronized; }
    }

    public object SyncRoot
    {
      get { return this.items.SyncRoot; }
    }

    #endregion

    #region IEnumerable Members

    public IEnumerator GetEnumerator()
    {
      return this.items.GetEnumerator();
    }

    #endregion

    public override string ToString()
    {
      StringBuilder s = new StringBuilder();

      for (int idx = 0; idx < this.items.Count; idx++)
        s.Append(this.items[idx].ToString());

      return s.ToString();
    }
  }

  /// <summary>
  /// Represents the base class for numerical objects in a PDF content stream.
  /// </summary>
  public class CNumber : CObject
  {
    /// <summary>
    /// Creates a new object that is a copy of the current instance.
    /// </summary>
    public new CNumber Clone()
    {
      return (CNumber)Copy();
    }

    /// <summary>
    /// Implements the copy mechanism of this class.
    /// </summary>
    protected override CObject Copy()
    {
      CObject obj = base.Copy();
      return obj;
    }
  }

  /// <summary>
  /// Represents an integer value in a PDF content stream.
  /// </summary>
  [DebuggerDisplay("({Value})")]
  public class CInteger : CNumber
  {
    /// <summary>
    /// Creates a new object that is a copy of the current instance.
    /// </summary>
    public new CInteger Clone()
    {
      return (CInteger)Copy();
    }

    /// <summary>
    /// Implements the copy mechanism of this class.
    /// </summary>
    protected override CObject Copy()
    {
      CObject obj = base.Copy();
      return obj;
    }

    /// <summary>
    /// Gets or sets the value.
    /// </summary>
    public int Value
    {
      get { return this.value; }
      set { this.value = value; }
    }
    int value;

    public override string ToString()
    {
      return this.value.ToString(CultureInfo.InvariantCulture);
    }
  }

  /// <summary>
  /// Represents a real value in a PDF content stream.
  /// </summary>
  [DebuggerDisplay("({Value})")]
  public class CReal : CNumber
  {
    /// <summary>
    /// Creates a new object that is a copy of the current instance.
    /// </summary>
    public new CReal Clone()
    {
      return (CReal)Copy();
    }

    /// <summary>
    /// Implements the copy mechanism of this class.
    /// </summary>
    protected override CObject Copy()
    {
      CObject obj = base.Copy();
      return obj;
    }

    /// <summary>
    /// Gets or sets the value.
    /// </summary>
    public double Value
    {
      get { return this.value; }
      set { this.value = value; }
    }
    double value;

    public override string ToString()
    {
      return this.value.ToString(CultureInfo.InvariantCulture);
    }
  }

  /// <summary>
  /// Represents a string value in a PDF content stream.
  /// </summary>
  [DebuggerDisplay("({Value})")]
  public class CString : CObject
  {
    /// <summary>
    /// Creates a new object that is a copy of the current instance.
    /// </summary>
    public new CString Clone()
    {
      return (CString)Copy();
    }

    /// <summary>
    /// Implements the copy mechanism of this class.
    /// </summary>
    protected override CObject Copy()
    {
      CObject obj = base.Copy();
      return obj;
    }

    /// <summary>
    /// Gets or sets the value.
    /// </summary>
    public string Value
    {
      get { return this.value; }
      set { this.value = value; }
    }
    string value;

    public override string ToString()
    {
      return "(" + this.value + ")";
    }
  }

  /// <summary>
  /// Represents a name in a PDF content stream.
  /// </summary>
  [DebuggerDisplay("({Name})")]
  public class CName : CObject
  {
    public CName()
    {
      this.name = "/";
    }

    public CName(string name)
    {
      Name = name;
    }

    /// <summary>
    /// Creates a new object that is a copy of the current instance.
    /// </summary>
    public new CName Clone()
    {
      return (CName)Copy();
    }

    /// <summary>
    /// Implements the copy mechanism of this class.
    /// </summary>
    protected override CObject Copy()
    {
      CObject obj = base.Copy();
      return obj;
    }

    /// <summary>
    /// Gets or sets the name.
    /// </summary>
    public string Name
    {
      get { return this.name; }
      set 
      {
        if (name == null || name.Length == 0)
          throw new ArgumentNullException("name");
        if (name[0] != '/')
          throw new ArgumentException(PSSR.NameMustStartWithSlash);
        this.name = value; 
      }
    }
    string name;

    public override string ToString()
    {
      return this.name;
    }
  }

  /// <summary>
  /// Represents an array of objects in a PDF content stream.
  /// </summary>
  [DebuggerDisplay("(count={Count})")]
  public class CArray : CSequence
  {
    /// <summary>
    /// Creates a new object that is a copy of the current instance.
    /// </summary>
    public new CArray Clone()
    {
      return (CArray)Copy();
    }

    /// <summary>
    /// Implements the copy mechanism of this class.
    /// </summary>
    protected override CObject Copy()
    {
      CObject obj = base.Copy();
      return obj;
    }

    public override string ToString()
    {
      return "[" + base.ToString() + "]";
    }
  }

  /// <summary>
  /// Represents an operator a PDF content stream.
  /// </summary>
  [DebuggerDisplay("({Name}, operands={Operands.Count})")]
  public class COperator : CObject
  {
    protected COperator()
    {
    }

    internal COperator(OpCode opcode)
    {
      this.opcode = opcode;
    }

    /// <summary>
    /// Creates a new object that is a copy of the current instance.
    /// </summary>
    public new COperator Clone()
    {
      return (COperator)Copy();
    }

    /// <summary>
    /// Implements the copy mechanism of this class.
    /// </summary>
    protected override CObject Copy()
    {
      CObject obj = base.Copy();
      return obj;
    }

    /// <summary>
    /// Gets or sets the name of the operator
    /// </summary>
    /// <value>The name.</value>
    public virtual string Name 
    {
      get { return this.opcode.Name; }
    }

    /// <summary>
    /// Gets or sets the operands.
    /// </summary>
    /// <value>The operands.</value>
    public CSequence Operands
    {
      get
      {
        if (this.seqence == null)
          this.seqence = new CSequence();
        return this.seqence;
      }
    }
    CSequence seqence;

    public OpCode OpCode
    {
      get { return this.opcode; }
    }
    OpCode opcode;


    public override string ToString()
    {
      return this.Name;
    }
  }

#if true_
  public class CGenericOperator : COperator
  {
    internal CGenericOperator(string name)
    {
      this.name = name;
    }

    /// <summary>
    /// Creates a new object that is a copy of the current instance.
    /// </summary>
    public new CGenericOperator Clone()
    {
      return (CGenericOperator)Copy();
    }

    /// <summary>
    /// Implements the copy mechanism of this class.
    /// </summary>
    protected override CObject Copy()
    {
      CObject obj = base.Copy();
      return obj;
    }

    /// <summary>
    /// Gets or sets the name of the operator
    /// </summary>
    /// <value>The name.</value>
    public override string Name
    {
      get { return this.name; }
    }
    string name;


    public override string ToString()
    {
      return this.Name;
    }
  }
#endif
}
