/// <summary>
		/// [R1 is deprecated use R2] Reads or regenerates an index for a field in a table
		/// </summary>
		/// <param name="TableName"></param>
		/// <param name="f"></param>
		/// <param name="bForceRegen"></param>
		/// <value></value>
		Index GetIndex(string TableName, Field f, bool bForceRegen)
		{
			const string FuncErrCode=ClassErrCode+".0015";
			try
			{
				lock(this.TableBlocking)
				{
					if(!this.TableBlocking.Contains(TableName))
						this.TableBlocking[TableName] = new SortedList();// index cache
				}
				lock(this.TableBlocking[TableName])
				{
					if((this.TableBlocking[TableName] as SortedList)[f.seq]!=null)
						return (this.TableBlocking[TableName] as SortedList)[f.seq] as Index;
					bool bRegen=true;
					if(!bForceRegen)
					{
						string indexname = TableName+".hi"+f.seq.ToString();
						if(IndexFileExists(indexname))
						{
							FileStream fs = FileStream2.NewFileStream(System.IO.Path.GetDirectoryName(DatabaseFilePath)+"\\"+indexname,FileMode.Open,FileAccess.ReadWrite,FileShare.None);
							BinaryReader br = new BinaryReader(fs);
							bool flag = br.ReadBoolean();
							if(flag)
							{
								bRegen=true;
							}
							else
							{
								bRegen=false;
//								SoapFormatter formatter = new SoapFormatter();
//								Index ndx = (Index)formatter.Deserialize(fs);
								Index ndx = Index.ReadIndexData(this,new BinaryReader(fs));
								(this.TableBlocking[TableName] as SortedList)[f.seq]=ndx;
							}
							fs.Close();
						}
					}
					if(bRegen)
					{// unique key
						if(!f.bIndexed) throw new Exception("Not indexed field");
						
						if(f.bUnique)
						{
							Index ndx = new Index();
							ndx.bUnique=true;
							CheckTable_FixContent(TableName,f); // por si las moscas
							FileStream fs = FileStream2.NewFileStream(System.IO.Path.GetDirectoryName(DatabaseFilePath)+"\\"+TableName+".hc"+f.seq.ToString(),FileMode.Open,FileAccess.Read,FileShare.None);
							BinaryReader br = new BinaryReader(fs);
							bool flag = br.ReadBoolean();
							if(flag)
							{
								throw new Exception("Database corruption");
							}
							else
							{
								HFI hfi = HFI.Read(TableName,DatabaseFilePath);
								for(long n=0;n<hfi.rowseq;n++)
								{
									object o = f.ReadData(this,br);
									ndx.ht[o]=n;
								}
								(this.TableBlocking[TableName] as SortedList)[f.seq]=ndx;
							}
							br.Close();
						}
						else
						{// not unique key
							Index ndx = new Index();
							ndx.bUnique=false;
							CheckTable_FixContent(TableName,f); // por si las moscas
							FileStream fs = FileStream2.NewFileStream(System.IO.Path.GetDirectoryName(DatabaseFilePath)+"\\"+TableName+".hc"+f.seq.ToString(),FileMode.Open,FileAccess.Read,FileShare.None);
							BinaryReader br = new BinaryReader(fs);
							bool flag = br.ReadBoolean();
							if(flag)
							{
								throw new Exception("Database corruption");
							}
							else
							{
								HFI hfi = HFI.Read(TableName,DatabaseFilePath);
								for(long n=0;n<hfi.rowseq;n++)
								{
									object o = f.ReadData(this,br);
									if(ndx.ht[o]==null)
										ndx.ht[o]=new ArrayList();
									(ndx.ht[o] as ArrayList).Add(n);
								}
								(this.TableBlocking[TableName] as SortedList)[f.seq]=ndx;
							}
							br.Close();
						}
					}
					return (this.TableBlocking[TableName] as SortedList)[f.seq] as Index;
				}
			}
			catch(Exception ex)
			{
				throw new Exception(ex.Message+"\n"+FuncErrCode+": Inner exception.");
			}
		}
		/// <summary>
		/// [R1 is deprecated use R2] Adds a field if it not exists
		/// </summary>
		public void AddFieldIfNotExist(string TableName, Field f)
		{
			const string FuncErrCode=ClassErrCode+".0018";
			try
			{
				lock(this.TableBlocking)
				{
					Field[] flds = this.GetFields(TableName);
					foreach(Field i in flds)
					{
						if(i.Name==f.Name)
							return;
					}
					this.AddField(TableName,f);
				}
			}
			catch(Exception ex)
			{
				throw new Exception(ex.Message+"\n"+FuncErrCode+": Inner exception.");
			}
		}
		/// <summary>
		/// [R1 is deprecated use R2] Fixes unfinished writes in a previous table grow
		/// </summary>
		/// <param name="TableName"></param>
		/// <param name="f"></param>
		unsafe internal void CheckTable_FixContent(string TableName, Field f)
		{
			const string FuncErrCode=ClassErrCode+".0013";
			try
			{
				lock(this.TableBlocking)
				{
					if(!this.TableBlocking.Contains(TableName))
						this.TableBlocking[TableName] = new SortedList();// index cache
				}
				lock(this.TableBlocking[TableName])
				{
					// Check content
					if(true)
					{
						FileStream fs = FileStream2.NewFileStream(System.IO.Path.GetDirectoryName(DatabaseFilePath)+"\\"+TableName+".hc"+f.seq.ToString(),FileMode.Open,FileAccess.ReadWrite,FileShare.None);
						BinaryReader br = new BinaryReader(fs);
						bool flag = br.ReadBoolean();
						if(flag)
						//if(true)
						{
							HFI hfi = HFI.Read(TableName,DatabaseFilePath);
							long supposedLen = (f.DataSize()*hfi.rowseq)+sizeof(bool);
							long offset=fs.Length-supposedLen;
							if(fs.Length<supposedLen)
							{
								// Recovering corrupt data
								long start = (fs.Length-sizeof(bool))/f.DataSize();
								fs.Position=start*f.DataSize()+sizeof(bool);
								BinaryWriter bw = new BinaryWriter(fs);
								for(long n=start;n<hfi.rowseq;n++)
								{
									f.WriteDefaultData(bw,false);
								}
								bw.Flush();
								bw.BaseStream.Position=0;
								bw.Write((bool)false); // edition flag
								bw.Flush();
								
								// Destroy the index
								if(f.bIndexed)
								{
									(TableBlocking[TableName] as SortedList)[f.seq]=null;
									SetDirtyIndexInDisc(TableName,f);
								}
								try
								{
									LogToFile("Warning","Recovering unfinished column.'"+TableName+"' by "+offset.ToString()+" bytes");
								}
								catch
								{
								}
							}
						}
						fs.Flush();
						fs.Close();
					}
				}
			}
			catch(Exception ex)
			{
				throw new Exception(ex.Message+"\n"+FuncErrCode+": Inner exception.");
			}
		}
		/// <summary>
		/// Invoked when in memory index is modified
		/// </summary>
		void SetDirtyIndexInDisc(string TableName, Field f)
		{
			const string FuncErrCode=ClassErrCode+".0012";
			try
			{
				string indexname = System.IO.Path.GetDirectoryName(DatabaseFilePath)+"\\"+TableName+".hi"+f.seq.ToString();
				FileStream fs = FileStream2.NewFileStream(indexname,FileMode.Open,FileAccess.Write,FileShare.None);
				BinaryWriter bw = new BinaryWriter(fs);
				bw.Write((bool)true);
				bw.Flush();
				bw.Close();
//
//				if(!Table2DeletedIndex.ContainsKey(indexname))
//				{
//					FileStream2.CloseHandle(indexname);
//					File.Delete(indexname);
//					Table2DeletedIndex[indexname]=0; // set the flag
//				}
			}
			catch(Exception ex)
			{
				throw new Exception(ex.Message+"\n"+FuncErrCode+": Inner exception.");
			}
		}
		/// <summary>
		/// [R1 is deprecated use R2] Get fieldnames of a table
		/// </summary>
		internal Field[] GetFields(string Name)
		{
			const string FuncErrCode=ClassErrCode+".0011";
			try
			{
				lock(this.TableBlocking)
				{
					if(FieldsCache[Name]==null)
					{
						string[] tblnames;
						GetTableNames(out tblnames);
						if(!new ArrayList(tblnames).Contains(Name))
							throw new Exception("HyperNetDatabase error: Table not present.");
						string tbl = Name;//Path.GetDirectoryName(DatabaseFilePath)+"\\"+Name;
						long fatid;
						if(true)
						{
							FileStream fs = FileStream2.NewFileStream(System.IO.Path.GetDirectoryName(DatabaseFilePath)+"\\"+tbl+".hfi",FileMode.Open,FileAccess.Read,FileShare.None);
							BinaryReader br = new BinaryReader(fs);
							if(br.ReadInt64()!=magic)
								throw new Exception("HyperNetDatabase error: Magic failed.");
							fatid = br.ReadInt64();
							br.Close();
						}
						if(true)
						{
							FileStream fs = FileStream2.NewFileStream(System.IO.Path.GetDirectoryName(DatabaseFilePath)+"\\"+tbl+".hf"+fatid.ToString(),FileMode.Open,FileAccess.Read,FileShare.None);
							BinaryReader br = new BinaryReader(fs,System.Text.Encoding.UTF8);
							br.ReadInt64(); // read magic
							long fields = br.ReadInt64();
							Field[] rv = new Field[fields];
							for(int n=0;n<fields;n++)
							{
								rv[n]=new Field();
								rv[n].Read(br);
							}
							br.Close();
							FieldsCache[Name]=rv;
							return rv;
						}
					}
					else
					{
						return (Field[])FieldsCache[Name];
					}
				}
			}
			catch(Exception ex)
			{
				throw new Exception(ex.Message+"\n"+FuncErrCode+": Inner exception.");
			}
		}
		/// <summary>
		/// [R1 is deprecated use R2] Adds a table
		/// </summary>
		public void AddField(string TableName, Field f)
		{
			const string FuncErrCode=ClassErrCode+".0010";
			try
			{
				lock(this.TableBlocking)
				{
					string[] tblnames;
					GetTableNames(out tblnames);
					if(!new ArrayList(tblnames).Contains(TableName))
						throw new Exception("HyperNetDatabase error: Table not present.");

					// set entry
					if(!this.TableBlocking.Contains(TableName))
						this.TableBlocking[TableName] = new SortedList();
				}
				lock(this.TableBlocking[TableName])
				{
					string tbl = TableName;
					QueryCacheDestroy(TableName);
					Field[] flds = GetFields(TableName);
					foreach(Field i in flds)
					{
						if(f.Name==i.Name)
							throw new Exception("HyperNetDatabase error: Column already present.");
					}
					FieldsCache[TableName]=null; // cancel Field Cache
					long fatid,rownum,fseq;
					HFI hfi = HFI.Read(tbl,DatabaseFilePath);
					fatid = hfi.fatid;
					
					rownum = hfi.rowseq;

					// gets new field seq
					fseq = hfi.fieldseq;
					hfi.fieldseq++;
					hfi.Write(tbl,DatabaseFilePath); 

					fatid = (fatid + 1) % 2;

					if(true)// Fat
					{
						// Create fat file
						FileStream fs = FileStream2.NewFileStream(System.IO.Path.GetDirectoryName(DatabaseFilePath)+"\\"+tbl+".hf"+fatid.ToString(),FileMode.Create,FileAccess.Write,FileShare.None);
						BinaryWriter bw = new BinaryWriter(fs,System.Text.Encoding.UTF8);
						bw.Write(magic);
						bw.Write((long)(flds.Length+1));
	 
						for(int n=0;n<flds.Length;n++)
							flds[n].Write(bw);
						f.seq=fseq;
						f.Write(bw);
						bw.Flush();
						bw.Close();
						

//						try
//						{
//
//							string fileName = System.IO.Path.GetDirectoryName(DatabaseFilePath)+"\\"+tbl+".hf"+((fatid + 1) % 2).ToString();
////							FileStream2.CloseHandle(fileName);
//							File.Delete(fileName);
//						}
//						catch
//						{
//						}

						// Create column data
						fs = FileStream2.NewFileStream(System.IO.Path.GetDirectoryName(DatabaseFilePath)+"\\"+tbl+".hc"+fseq.ToString(),FileMode.Create,FileAccess.Write,FileShare.None);
						bw = new BinaryWriter(fs,System.Text.Encoding.UTF8);
						bw.Write((bool)true); // edition flag
						bw.Flush();
						for(int n=0;n<rownum;n++)
						{
							f.WriteDefaultData(bw,false);
						}
						bw.Flush();
						bw.BaseStream.Position=0;
						bw.Write((bool)false); // edition flag
						bw.Flush();
						bw.Close();

						// Change fat pointer
						hfi.fatid=fatid;
						hfi.Write(tbl,DatabaseFilePath);
					}

				}
			}
			catch(Exception ex)
			{
				throw new Exception(ex.Message+"\n"+FuncErrCode+": Inner exception.");
			}
		}
		/// <summary>
		/// Adds a table
		/// </summary>
		public void AddTable(string Name)
		{
			const string FuncErrCode=ClassErrCode+".0008";
			try
			{
				lock(this.TableBlocking)
				{
					string[] tblnames;
					GetTableNames(out tblnames);
					if(new ArrayList(tblnames).Contains(Name))
						throw new Exception("HyperNetDatabase error: Table already present.");
					string tbl = Name;//Path.GetDirectoryName(DatabaseFilePath)+"\\"+Name;
					if(true)// Fat0
					{
						FileStream fs = FileStream2.NewFileStream(System.IO.Path.GetDirectoryName(DatabaseFilePath)+"\\"+tbl+".hf0",FileMode.Create,FileAccess.Write,FileShare.None);
						BinaryWriter bw = new BinaryWriter(fs);
						bw.Write(magic);
						bw.Write((long)0); // zero fields
						bw.Write((long)0); // FieldSeq number
						bw.Flush();
						bw.Close();
					}
					// Create field defs file (HyperFieldIndex)
					new HFI().Write(tbl,DatabaseFilePath);

					Field f = new Field(DeletedFieldName,true,FieldIndexing.IndexedNotUnique);
					AddField(tbl,f);
				}
			}
			catch(Exception ex)
			{
				throw new Exception(ex.Message+"\n"+FuncErrCode+": Inner exception.");
			}
		}