/*    
   Defrmap.c - speed up bitfields.

   Copyright (C) 2003 Imre Leber

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

   If you have any questions, comments, suggestions, or fixes please
   email me at:  imre.leber@worldonline.be
*/

#include <stdlib.h>

#include "fte.h"
#include "..\dtstruct\ClMovMap.h"
#include "unfrgfls\IsFlFgtd.h"

static BOOL FirstClusterMarker(RDWRHandle handle, 
                               struct DirectoryPosition* pos,
                               void** structure);
static BOOL ContinousFileMarker(RDWRHandle handle, 
                                struct DirectoryPosition* pos,
                                void** structure);
static BOOL ContinousClusterMarker(RDWRHandle handle, CLUSTER label,
                                   SECTOR datsector, void** structure);                                
                               

static char* FastSelectMap = NULL;
static char* NotFragmentedMap = NULL;

BOOL CreateFastSelectMap(RDWRHandle handle)
{
     unsigned long LabelsInFat;
     
     LabelsInFat = GetLabelsInFat(handle);
     if (!LabelsInFat) return FAIL;
        
     FastSelectMap = CreateBitField(LabelsInFat);
     if (!FastSelectMap) return FALSE;
     
     if (!WalkDirectoryTree(handle, FirstClusterMarker, (void**) NULL))
        return FAIL;
        
     return TRUE;
}

static BOOL FirstClusterMarker(RDWRHandle handle, 
                               struct DirectoryPosition* pos,
                               void** structure)
{
    CLUSTER cluster;
    struct DirectoryEntry entry;
    BOOL isMovable;
    
    if (structure);
     
    if (!GetDirectory(handle, pos, &entry))
    {
       return FAIL;
    }

    /*
       Don't take LFN entries into consideration.
    */
    if (IsLFNEntry(&entry)) return TRUE;

    /*
       Be carefull for hidden or system files.
    */
    if ((entry.attribute & FA_HIDDEN) || (entry.attribute & FA_SYSTEM) ||
        IsDeletedLabel(entry))
    {
       return TRUE;
    }     
    
    cluster = GetFirstCluster(&entry);
    if (cluster)
    {
       if (!IsClusterMovable(handle, cluster, &isMovable))
          return FAIL;

       if (isMovable)
       {
          SetBitfieldBit(FastSelectMap, cluster);
       }
    }
    
    return TRUE;
}

void DestroyFastSelectMap(void)
{
    if (FastSelectMap)
    {
       DestroyBitfield(FastSelectMap);
       FastSelectMap = NULL;
    }
}

char* GetFastSelectMap(void)
{
    return FastSelectMap;
}

void SwapClustersInFastSelectMap(CLUSTER cluster1, CLUSTER cluster2)
{
     if (!FastSelectMap) return;
     
     SwapBitfieldBits(FastSelectMap, cluster1, cluster2);

     if (NotFragmentedMap)
        SwapBitfieldBits(NotFragmentedMap, cluster1, cluster2);
}

BOOL CreateNotFragmentedMap(RDWRHandle handle)
{
     unsigned long LabelsInFat;
     
     LabelsInFat = GetLabelsInFat(handle);
     if (!LabelsInFat) return FAIL;
        
     NotFragmentedMap = CreateBitField(LabelsInFat);
     if (!NotFragmentedMap) return FALSE;

     if (!WalkDirectoryTree(handle, ContinousFileMarker, (void**) NULL))
        return FAIL;
        
     return TRUE;    
}

void DestroyNotFragmentedMap()
{
     if (NotFragmentedMap)
     {
	free(NotFragmentedMap);
	NotFragmentedMap = NULL;
     }
}

static BOOL ContinousFileMarker(RDWRHandle handle, 
                                struct DirectoryPosition* pos,
                                void** structure)
{
    CLUSTER cluster;
    struct DirectoryEntry entry;
    BOOL isMovable;
    
    if (structure);
     
    if (!GetDirectory(handle, pos, &entry))
    {
       return FAIL;
    }

    /*
       Don't take LFN entries into consideration.
    */
    if (IsLFNEntry(&entry)) return TRUE;

    /*
       Be carefull for hidden or system files.
    */
    if ((entry.attribute & FA_HIDDEN) || (entry.attribute & FA_SYSTEM) ||
        IsDeletedLabel(entry))
    {
       return TRUE;
    }     
    
    cluster = GetFirstCluster(&entry);
    if (cluster)
    {
       if (!IsClusterMovable(handle, cluster, &isMovable))
          return FAIL;

       if (isMovable)
       {
          switch (IsFileFragmented(handle, cluster))
          {
            case FALSE:
                 if (!FileTraverseFat(handle, cluster, 
                                      ContinousClusterMarker,
                                      (void**) NULL))
                 {
                    return FAIL;
                 }
                 break;
                 
            case FAIL:
                 return FAIL;
          }
       }
    }
    
    return TRUE;     
}     

static BOOL ContinousClusterMarker(RDWRHandle handle, CLUSTER label,
                                   SECTOR datasector, void** structure)  
{
    CLUSTER cluster;
    
    if (label);
    if (structure);
    
    cluster = DataSectorToCluster(handle, datasector);
    if (!cluster) return FAIL;
      
    SetBitfieldBit(NotFragmentedMap, cluster);
    ClearBitfieldBit(FastSelectMap, cluster);
    
    return TRUE;
}

char* GetNotFragmentedMap(void)
{
    return NotFragmentedMap; 
}

void MarkFileAsContinous(CLUSTER place, unsigned long length)
{
     unsigned long i;
     
     for (i = 0; i < length; i++)
     {
	 SetBitfieldBit(NotFragmentedMap, place+i);
	 ClearBitfieldBit(FastSelectMap, place+i);
     }
}