#
# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved.
# This component and the accompanying materials are made available
# under the terms of "Eclipse Public License v1.0"
# which accompanies this distribution, and is available
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
#
# Initial Contributors:
# Nokia Corporation - initial contribution.
#
# Contributors:
#
# Description: 
#

use strict;

use Getopt::Long;
use File::Path;
use File::Spec::Functions;

my $gRealTimeBuildErrors = 0;
sub RealTimeBuildError($)
{
	$gRealTimeBuildErrors++;
	print STDERR "ERROR: RealTimeBuild: ", @_, "\n";
	return "RealTimeBuild error";
}

# Process the commandline
my ($iDataSource, $iSrc, $iMRPSrc, $platform, $iDummy, $iVerbose) = ProcessCommandLine();

my ($iDirList)= ProcessList($iDataSource, $iSrc, $iMRPSrc, $platform, $iVerbose);
my @delete;

search_dir($iSrc, $iDirList, \@delete, $iVerbose);

foreach my $leftover (keys %$iDirList)
{
  print "REMARK: LEFTOVER: $leftover ($$iDirList{$leftover})\n";
}

if ($gRealTimeBuildErrors && !$iDummy)
{
  print STDERR "\nWARNING: Files will NOT be deleted, because of earlier real time build errors\n\n";
  $iDummy = 1;
}

foreach my $delete (@delete)
{
  if ($iDummy)
  {
    print "REMARK: $delete is not referenced by any MRP\n";
  } else {
    # Delete the files or directories
    # make sure it is not read only
    #Convert back to \ for dos command
    $delete =~ s#\/#\\#g;
    system("attrib -r /s /d \"$delete\"");
    my $deletenum = rmtree($delete);
    if ($deletenum == 0)
    {
      RealTimeBuildError("failed to deleted $delete");
    } elsif (-d "$delete") {
      RealTimeBuildError("failed to deleted directory $delete"); #Because it still exists
    } elsif ($deletenum > 1) {
      print "REMARK: deleted $deletenum files in directory $delete as they are not referenced by any MRP\n";
    } else {
      print "REMARK: deleted $delete as it is not referenced by any MRP\n";
    }
  }
}

sub search_dir
{ 
  my ($dir, $iDirList, $delete, $iVerbose) = @_; 
  my @flist;
  
  print "Processing $dir\n" if ($iVerbose);
  if (opendir(DIRH,"$dir"))
  {
    @flist=readdir(DIRH); 
    closedir DIRH; 
    ENTRY: foreach my $entry (@flist)
    { 
      # ignore . and .. : 
      next if ($entry eq "." || $entry eq "..");
      my $partial_match;
      # Check entry again $iDirList for matches
      foreach my $sourceline (keys %$iDirList)
      {
        if ($sourceline =~ m#^$dir/$entry$#i)
        {
          # Exact match delete entry in %$iDirList
          # Check to see if something has already partial matched
          print "REMARK: $dir/$entry is probably covered more than once\n" if ($partial_match);
          if ($iVerbose)
          {
            if (-d "$dir/$entry")
            {
              print "Keeping directory $dir/$entry ($$iDirList{$sourceline})\n";
            } else {
              print "Keeping file $dir/$entry ($$iDirList{$sourceline})\n";
            }
          }
          delete $$iDirList{$sourceline};
          # No more processing required
          next ENTRY;
        }
        # Check to see if there is reference to inside this directory
        if ($sourceline =~ m#^$dir/$entry/#i)
        {
          # something reference this as a directory need more processing
          $partial_match = 1 if (-d "$dir/$entry");
        }
      }
      if ($partial_match)
      {
        search_dir("$dir/$entry", $iDirList, $delete, $iVerbose) if (-d "$dir/$entry");
        next ENTRY;
      }
      # No match place on deletion list
      push @$delete, "$dir/$entry";
      print "Marking $dir/$entry for delete\n" if ($iVerbose);
    }
  }else{ 
    RealTimeBuildError("can not read directory $dir"); 
  } 
}

# ProcessList
#
# Inputs
# $iDataSource - ref to array of files to process
# $iSrc - real location of source files
# $iMRPSrc - where the mrp thinks they are
#
# Outputs
#
# Description
# This function processes mrp files
sub ProcessList
{
  my ($iDataSource, $iSrc, $iMRPSrc, $platform, $iVerbose) = @_;
  
  my %Sources;
  my @ComponentList;
  my %mrpHash;
  
  # Need the dir swap
  $iDataSource =~ s/^$iMRPSrc/$iSrc/;
  # Read the options.txt
  open OPTIONS, $iDataSource or die RealTimeBuildError("Cannot open $iDataSource $!");
  while(<OPTIONS>)
  {
    if (/^GT\+Techview baseline mrp location:\s*(\S+)\s*$/i)
    {
      $mrpHash{lc $1} = $1;
      next;
    }
    if (/^GT only baseline mrp location:\s*(\S+)\s*$/i)
    {
      $mrpHash{lc $1} = $1;
      next;
    }
    if (/^Strong crypto mrp location:\s*(\S+)\s*$/i)
    {
      $mrpHash{lc $1} = $1;
      next;
    }
    if (/^Techview component list:\s*(\S+)\s*$/i)
    {
      push @ComponentList, $1;
      next;
    }
    if (/^GT component list:\s*(\S+)\s*$/i)
    {
      push @ComponentList, $1;
      next;
    }
  }
  close OPTIONS;
  for (my $i = 0; $i < scalar(@ComponentList); $i++)
  {
    # Fix path
    $ComponentList[$i] =~ s#\\#\/#g;
    # Need the dir swap
    $ComponentList[$i] =~ s/^$iMRPSrc/$iSrc/;
    open IN, $ComponentList[$i] or die RealTimeBuildError("Cannot open ".$ComponentList[$i]." $!");
    while(<IN>)
    {
      my ($mrp) = /^\s*\S+\s+(\S+)\s*$/;
      $mrpHash{lc $mrp} = $mrp;
    }
    close IN;
  }

  my @mrpList = sort values %mrpHash;
  for (my $i = 0; $i < scalar(@mrpList); $i++)
  {
    # Fix path
    $mrpList[$i] =~ s#\\#\/#g;
    # Need the dir swap
    $mrpList[$i] =~ s/^$iMRPSrc/$iSrc/i;
    # Fix the CustKit / Devkit and techviewexamplesdk mrp locations
    $mrpList[$i] =~ s#^/product/CustKit#$iSrc/os/unref/orphan/cedprd/CustKit#i;
    $mrpList[$i] =~ s#^/product/DevKit#$iSrc/os/unref/orphan/cedprd/DevKit#i;
    $mrpList[$i] =~ s#^/product/techviewexamplesdk#$iSrc/os/unref/orphan/cedprd/techviewexamplesdk#i;
    $Sources{"$iSrc/os/unref/orphan/cedprd/SuppKit"} = "clean.pl";
    $Sources{"$iSrc/os/unref/orphan/cedprd/tools"} = "clean.pl";
    $Sources{"$iSrc/os/buildtools/toolsandutils/productionbldtools"} = "clean.pl";
    
    if (open MRP, $mrpList[$i])
    {
      my $mrpfile = $mrpList[$i];
      my $mrpfile_in_source = 0;
      
      while(<MRP>)
      {
        my $dir;
        if (/^\s*source\s+(\S.*\S)\s*$/i)		# must allow for spaces in names
        {
          my $origdir = $1;
          $dir = $origdir;
         
          #Find any relative paths and add them to the end of the mrp location to create a full path
          if (($dir =~ /\.\\/)||($dir =~ /\.\.\\/)||($dir !~ /\\/))
          {
		  $dir =~ s#\.\.#\.#g;		# .. becomes .	
		  $dir =~ s#^\.#\\\.#g;		# add an extra \ incase one is not present at start of path, canonpath wil cleanup multiple \
	  
		  $dir = "\\".$dir if ($dir !~ /\\/);	#add \ to start of path if source line only specifies a file
		  
		  # Fix paths to /
		  $dir =~ s#\\#\/#g;
		  
		  $dir =~ s/$iMRPSrc/$iSrc/i if ($dir =~ /^$iMRPSrc/);
		  
		  $dir = $iSrc.$dir if ($dir !~ /^$iMRPSrc/);
		  
		  $dir = canonpath($dir);
          }
	  
	  # Fix paths to /
	  $dir =~ s#\\#\/#g;
	  
          # Remove any / from the end of the sourceline just in case the directory was ended in one
          $dir =~ s#\/$##;
          # Need the dir swap
          $dir =~ s/^$iMRPSrc/$iSrc/i;
          # Fix the CustKit / Devkit and techviewexamplesdk mrp locations
          $dir =~ s#^/product/CustKit#$iSrc/os/unref/orphan/cedprd/CustKit#i;
          $dir =~ s#^/product/DevKit#$iSrc/os/unref/orphan/cedprd/DevKit#i;
          $dir =~ s#^/product/techviewexamplesdk#$iSrc/os/unref/orphan/cedprd/techviewexamplesdk#i;
          
          if ($mrpfile =~ /^$dir$/i || $mrpfile =~ /^$dir\//i) {
            # mrpfile covered by source statements
            $mrpfile_in_source = 1;
          }

          # ignore location of release notes
          next if ($dir =~ /^\/component_defs/i);
          
          if (!-e $dir) {
            # CBR tools consider missing source as a fatal error
            RealTimeBuildError("$dir does not exist (listed as source in $mrpfile)");
          } elsif (!defined $Sources{$dir}) {
            $Sources{$dir} = $mrpfile;
          } else {
            print "REMARK: $origdir in $mrpfile is already defined in $Sources{$dir}\n";
          }
        }
      }
      close MRP;
      print "REMARK: $mrpList[$i] does not include itself as source\n" if (!$mrpfile_in_source);
    } else {
      RealTimeBuildError("Cannot open ".$mrpList[$i]." $!");
    }
  }
  return \%Sources;
}

# ProcessCommandLine
#
# Inputs
#
# Outputs
# @iDataSource array of multiple (txt file(s) to process)
# $iSrc - real location of files
# $iMRPSrc - where the mrp thinks they are
# @iDummy - do not delete anything
#
# Description
# This function processes the commandline

sub ProcessCommandLine {
  my ($iHelp, $iDataSource, $iSrc, $iMRPSrc, $platform, $iDummy, $iVerbose);
  GetOptions('h' => \$iHelp, 'o=s' =>\$iDataSource, 's=s' =>\$iSrc, 'm=s' =>\$iMRPSrc, 'p=s' =>\$platform,'n' => \$iDummy, 'v' => \$iVerbose);

  if (($iHelp) || (!defined $iSrc) || (!defined $iMRPSrc) || (!defined $platform))
  {
    Usage();
  }

  die RealTimeBuildError("Source directory $iSrc must be an absolute path with no drive letter") if ($iSrc !~ m#^[\\\/]#);
  die RealTimeBuildError("Source directory $iMRPSrc must be an absolute path with no drive letter") if ($iMRPSrc !~ m#^[\\\/]#);
  # Fix the paths
  $iSrc =~ s#\\#\/#g;
  $iMRPSrc =~ s#\\#\/#g;
  $iDataSource =~ s#\\#\/#g;
  if (! -d "$iSrc")
  {
    die RealTimeBuildError("$iSrc is not a directory") ;
  }

  # Need the dir swap
  $iDataSource =~ s/^$iMRPSrc/$iSrc/i;
  if (! -e "$iDataSource")
  {
    die RealTimeBuildError("Cannot open $iDataSource");
  }

  return($iDataSource, $iSrc, $iMRPSrc, $platform, $iDummy, $iVerbose);
}

# Usage
#
# Output Usage Information.
#

sub Usage {
  print <<USAGE_EOF;

  Usage: clean.pl [options]

  options:

  -h  help
  -o  options.txt to process
  -s  Source directory to process
  -m  MRP source directory
  -p  platform of product (beech or cedar)
  -n  Not do anything (dummy run)
  -v  Verbose
  
  Note:
  Due to CustKit using the clean-src directory (%clean-src%) for source
  The files need to be deleted from the %clean-src% directory
  This tool substitutes directory specified by -m with the directory
  specified by -s in all locations
  This means that options.txt and the component lists and mrp's must be
  referenced in the directory
  specified by -m

USAGE_EOF
  exit 1;
}