/*    
   FllDfrg.c - code to fully optimize a drive.

   Copyright (C) 2002 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 <string.h>
#include <stdio.h>

#include "fte.h"
#include "DfrgDrvr.h"
#include "FllDfrag\flldfrg.h"
#include "..\dtstruct\ClMovMap.h"
#include "..\..\modlgate\expected.h"
#include "defrmap.h"

/* Public functions */
static BOOL SelectFile(RDWRHandle handle, CLUSTER startfrom,
                       CLUSTER* clustertoplace);                         

struct Pipe
{
   CLUSTER cluster;
   CLUSTER clustertoplace;

   BOOL found;
};

BOOL FullyDefragmentVolume(RDWRHandle handle)
{
    BOOL result;
    
    if (CreateFastSelectMap(handle) == FAIL)
       return FALSE;
    
    result = DefragmentVolume(handle, SelectFile, FullDefragPlace);
    
    DestroyFastSelectMap();
    
    return result;
}

static BOOL SelectFile(RDWRHandle handle, CLUSTER startfrom,
                       CLUSTER* clustertoplace)
{
    CLUSTER i;
    unsigned long LabelsInFat;
    char* FastSelectMap;
    
    LabelsInFat = GetLabelsInFat(handle);
    if (!LabelsInFat) return FAIL;

    FastSelectMap = GetFastSelectMap();
    for (i = startfrom; i < LabelsInFat; i++)
    {
        if (GetBitfieldBit(FastSelectMap, i))
        {
           *clustertoplace = i;
           return TRUE;
        }
    }
    
    return FALSE;
}

BOOL FullDefragPlace(RDWRHandle handle, CLUSTER clustertoplace,
                     CLUSTER clustertobereplaced, CLUSTER* stop)
{
    BOOL pastTheEnd = FALSE, isMovable;
    CLUSTER label;

    /*
        Now try moving all the clusters to the front of the disk:
        - If the target cluster is free, just move it to the given location.
        - If the target cluster is not movable go on to the next cluster.
        - Otherwise swap the target cluster with the cluster in the file
          to defragment.
        - Do not move bad clusters.
        - Do not swap a cluster with itself.
    */
    
//    filelen = CalculateFileSize(handle, clustertoplace);
//    if (filelen == FAIL) return FAIL;

//    if (!PreReadClusterSequence(handle, clustertobereplaced, filelen))
//       return FAIL;
//    if (!PreReadClusterChain(handle, clustertoplace))
//       return FAIL;
    
    clustertobereplaced--;
    while (!pastTheEnd)
    {
        do {
	   clustertobereplaced++;

           if (!GetNthCluster(handle, clustertobereplaced, &label))
              return FAIL;     

	   /* See wether the cluster is movable */
	   if (!IsClusterMovable(handle, clustertobereplaced, &isMovable))
	      return FAIL;

	} while (FAT_BAD(label) || !isMovable);

        DrawOnDriveMap(clustertoplace, READSYMBOL);
        DrawOnDriveMap(clustertobereplaced, WRITESYMBOL);

        SwapClustersInFastSelectMap(clustertoplace, clustertobereplaced);
        
	if (FAT_FREE(label))
	{
           if (!RelocateCluster(handle, clustertoplace, clustertobereplaced))
	      return FAIL;

           DrawOnDriveMap(clustertoplace, UNUSEDSYMBOL);
           DrawOnDriveMap(clustertobereplaced, OPTIMIZEDSYMBOL);
	}
	else
	{
	   if (clustertoplace != clustertobereplaced)
	   {
              if (!SwapClusters(handle, clustertoplace, clustertobereplaced))
                 return FAIL;
           }
           
           DrawOnDriveMap(clustertoplace, USEDSYMBOL);
           DrawOnDriveMap(clustertobereplaced, OPTIMIZEDSYMBOL);
        }
	clustertoplace = GetNthFileCluster(handle, clustertobereplaced, 1,
					   &pastTheEnd);
	if (!clustertoplace) return FAIL;
    }

    *stop = clustertobereplaced+1;
    return TRUE;
}
