context: // 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.
  //
  // Copyright (c) 2008 Novell, Inc.
  //
  // Authors:
  //	Andreia Gaita (avidigal@novell.com)
  //
  
  using System;
  using System.Collections;
  using Mono.WebBrowser;
  using Mono.WebBrowser.DOM;
  
  namespace Mono.Mozilla.DOM
  {
  	internal class WindowCollection : DOMObject, IWindowCollection
  	{
  		protected nsIDOMWindowCollection unmanagedWindows;
  		protected IWindow [] windows;
  		protected int windowCount;
  		
  		public WindowCollection (WebBrowser control, nsIDOMWindowCollection windowCol) : base (control)
  		{
  			if (control.platform != control.enginePlatform)
  				unmanagedWindows = nsDOMWindowCollection.GetProxy (control, windowCol);
  			else
  				unmanagedWindows = windowCol;
  		}
  
  		public WindowCollection (WebBrowser control) : base (control)
  		{
  			windows = new Window[0];
  		}
  		
  		#region IDisposable Members
  		protected override  void Dispose (bool disposing)
  		{
  			if (!disposed) {
  				if (disposing) {
  					Clear ();
  				}
  			}
  			base.Dispose(disposing);
  		}		
  		#endregion
  
  		#region Helpers
  		protected void Clear () 
  		{
  			if (windows != null) {
  				for (int i = 0; i < windowCount; i++) {
  					windows[i] = null;
  				}
  				windowCount = 0;
  				windows = null;
  			}
  		}
  
  		internal void Load ()
  		{
  			Clear ();
  			uint count;
  			unmanagedWindows.getLength (out count);
  			Window[] tmpwindows = new Window[count];
  			for (int i = 0; i < count;i++) {
  				nsIDOMWindow window;
  				unmanagedWindows.item ((uint)i, out window);
  				tmpwindows[windowCount++] = new Window (control, (nsIDOMWindow)window);
  			}
  			windows = new Window[windowCount];
  			Array.Copy (tmpwindows, windows, windowCount);
  		}
  		#endregion
  		
  		#region IEnumerable members
  		public IEnumerator GetEnumerator () 
  		{
  			return new WindowEnumerator (this);
  		}
  		#endregion
  		
  		#region ICollection members
  		public void CopyTo (Array dest, int index) 
  		{
  			if (windows != null) {
  				Array.Copy (windows, 0, dest, index, windowCount);
  			}
  		}
  	
  		public int Count {
  			get {
  				if (unmanagedWindows != null && windows == null)
  					Load ();
  				return windowCount; 
  			}
  		}
  		
  		object ICollection.SyncRoot {
  			get { return this; }
  		}
  		
  		bool ICollection.IsSynchronized {
  			get { return false; }
  		}
  
  		#endregion
  		
  		#region IList members
  		public bool IsReadOnly 
  		{
  			get { return false;}
  		}
  
  		bool IList.IsFixedSize 
  		{
  			get { return false;}
  		}
  
  		void IList.RemoveAt  (int index) 
  		{
  			RemoveAt (index);			
  		}
  		
  		public void RemoveAt (int index)
  		{
  			if (index > windowCount || index < 0)
  				return;			
  			Array.Copy (windows, index + 1, windows, index, (windowCount - index) - 1);
  			windowCount--;
  			windows[windowCount] = null;
  		}
  		
  		public void Remove (IWindow window) 
  		{
  			this.RemoveAt (IndexOf (window));
  		}
  
  		void IList.Remove (object window) 
  		{
  			Remove (window as IWindow);
  		}
  		
  		public void Insert (int index, IWindow value) 
  		{
  			if (index > windowCount)
  				index = windowCount;
  			IWindow[] tmp = new Window[windowCount+1];
  			if (index > 0)
  				Array.Copy (windows, 0, tmp, 0, index);
  			tmp[index] = value;
  			if (index < windowCount)
  				Array.Copy (windows, index, tmp, index + 1, (windowCount - index));
  			windows = tmp;
  			windowCount++;
  		}
  
  		void IList.Insert (int index, object value) 
  		{
  			this.Insert (index, value as IWindow);
  		}
  		
  		public int IndexOf (IWindow window) 
  		{
  			return Array.IndexOf (windows, window);
  		}
  
  		int IList.IndexOf (object window) 
  		{
  			return IndexOf (window as IWindow);
  		}
  		
  		
  		public bool Contains (IWindow window)
  		{
  			return this.IndexOf (window) != -1;
  		}
  		
  		bool IList.Contains (object window)
  		{
  			return Contains (window as IWindow);			
  		}
  		
  		void IList.Clear () 
  		{
  			this.Clear ();
  		}
  		
  		public int Add (IWindow window) 
  		{
  			this.Insert (windowCount + 1, window as IWindow);
  			return windowCount - 1;
  		}
  		
  		int IList.Add (object window) 
  		{
  			return Add (window as IWindow);
  		}
  		
  		object IList.this [int index] {
  			get { 
  				return this [index]; 
  			}
  			set { 
  				this [index] = value as IWindow; 
  			}
  		}
  		
  		public IWindow this [int index] {
  			get {
  				if (index < 0 || index >= windowCount)
  					throw new ArgumentOutOfRangeException ("index");
  
gt: 				return windows [index];								