/*
**  Container.m
**
**  Copyright (c) 2002
**
**  Author: Ludovic Marcotte <ludovic@Sophos.ca>
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**  
**  This library 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
**  Lesser General Public License for more details.
**  
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <Pantomime/Container.h>

#include <Pantomime/Constants.h>
#include <Pantomime/InternetAddress.h>
#include <Pantomime/Message.h>

#include <Foundation/NSDebug.h>

@implementation Container

//
//
//
- (id) init
{
  self = [super init];

  message = nil;
  parent = nil;
  child = nil;
  next = nil;
  visible = YES;

  return self;
}


//
//
//
- (void) dealloc
{
  NSDebugLog(@"Container: -dealloc");

  TEST_RELEASE(parent);
  TEST_RELEASE(child);
  TEST_RELEASE(next);

  [super dealloc];
}


//
// access / mutation methods
//
- (void) setParent: (Container *) theParent
{
  if ( theParent )
    {
      RETAIN(theParent);
      RELEASE(parent);
      parent = theParent;
    }
  else
    {
      DESTROY(parent);
    }
}


// 
// FIXME: Fix mem leaks
//
- (void) setChild: (Container *) theChild
{
  if ( !theChild || theChild == self || theChild->next == self || theChild == child )
    {
      NSDebugLog(@"Attempted to set self as a child!");
      return;
    }
  
  if ( theChild )
    {
      Container *aChild;

      // We search down in the children of theChild to be sure that
      // self IS NOT reachable
      // FIXME - we should use childrenEnumerator since we are NOT looping
      // in all children with this code
      aChild = theChild->child;

      while ( aChild )
      	{
      	  if ( aChild == self )
      	    {
      	      NSDebugLog(@"Trying to add a loop, breaking it.");
      	      return;
      	    }
	  
	  aChild = aChild->next;
      	}


      RETAIN(theChild);
      //RELEASE(child);
      //child = theChild;
      
      // We finally add it!
      NSDebugLog(@"Adding child |%d, %@| to %d", theChild->message, [theChild->message subject], message);

      if ( !child )
	{
	  child = theChild;
	}
      else
	{	  
	  aChild = child;

	  // We go at the end of our list of children
	  //while ( aChild->next != nil && aChild->next != aChild )
	  while ( aChild->next != nil )
	    {
	      NSDebugLog(@"Looping, child |%d, %@| %d and %d", 
			 aChild->message, 
			 [aChild->message subject],
			 [aChild->message messageNumber]);
	      
	      if ( aChild->next == aChild )
		{
		  aChild->next = theChild;
		  return;
		}

	      // We don't add the child if it's already there
	      if ( aChild == theChild )
		{
		  NSDebugLog(@"Trying to add a child already there");
		  return;
		}

	      aChild = aChild->next;
	    }

	  aChild->next = theChild;
	}
   
    }
  else
    {
      DESTROY(child);
    }
}


//
//
//
- (Container *) childAtIndex: (int) theIndex
{
  Container *aChild;
  int i;

  aChild = child;

  for (i = 0; i < theIndex; i++)
    {
      // If the child isn't visible, we skip it
      if ( !aChild->visible )
	{
	  NSLog(@"Not visible in childAtIndex, we skip it");
	  aChild = aChild->next;
	}
      
      aChild = aChild->next;
    }

  return aChild;
}


//
//
//
- (int) count
{
  if ( child )
    {
      Container *aChild;
      int count;

      aChild = child;
      count = 0;

      while ( aChild )
	{
	  NSDebugLog(@"counting, count = %d", count);
	  
	  //if ( aChild == self || aChild->next == aChild )
	  if ( aChild == self )
	    {
	      count = 1;
	      break;
	    }

	  if ( aChild->visible )
	    {
	      count++;
	    }
	  else
	    {
	      NSLog(@"Not visible in count, we skip it");
	    }

	  aChild = aChild->next;
	}

      return count;
    }
  
  return 0;
}


//
//
//
- (void) setNext: (Container *) theNext
{
  if ( theNext )
    {
      RETAIN(theNext);
      RELEASE(next);
      next = theNext;
    }
  else
    {
      DESTROY(next);
    }
}


//
//
//
- (NSEnumerator *) childrenEnumerator
{
  NSMutableArray *aMutableArray;
  Container *aContainer;

  aMutableArray = [[NSMutableArray alloc] init];
  AUTORELEASE(aMutableArray);

  aContainer = child;
  
  while ( aContainer )
    {
      [aMutableArray addObject: aContainer];
      
      // We add, recursively, all its children
      [aMutableArray addObjectsFromArray: [[aContainer childrenEnumerator] allObjects]];

      // We get our next container
      aContainer = aContainer->next;
    }

  return [aMutableArray objectEnumerator];
}

@end


//
// Container's sorting category
//
@implementation Container (Comparing)

// 
// FIXME - Also sort children
//
- (int) compareAccordingToNumber: (Container *) aContainer
{
  int num1, num2;
  
  num1 = [message messageNumber];
  num2 = [aContainer->message messageNumber];
  
  if (num1 < num2)
    {
      return NSOrderedAscending;
    }
  else if (num1 > num2)
    {
      return NSOrderedDescending;
    }
  else
    {
      return NSOrderedSame;
    }
}

- (int) reverseCompareAccordingToNumber: (Container *) aContainer
{
  int num1, num2;

  num2 = [message messageNumber];
  num1 = [aContainer->message messageNumber];
  
  if (num1 < num2)
    {
      return NSOrderedAscending;
    }
  else if (num1 > num2)
    {
      return NSOrderedDescending;
    }
  else
    {
      return NSOrderedSame;
    }
}

- (int) compareAccordingToDate: (Container *) aContainer
{
  NSTimeInterval timeInterval;
  NSDate *date1, *date2;

  date1 = [message receivedDate];
  date2 = [aContainer->message receivedDate];
  
  if (date1 == nil || date2 == nil)
    {
      return [self compareAccordingToNumber: aContainer]; 
    }

  timeInterval = [date1 timeIntervalSinceDate: date2];

  if (timeInterval < 0)
    {
      return NSOrderedAscending;
    }
  else if (timeInterval > 0)
    {
      return NSOrderedDescending;
    }
  else
    {
      return [self compareAccordingToNumber: aContainer];      
    }
}

- (int) reverseCompareAccordingToDate: (Container *) aContainer
{
  NSTimeInterval timeInterval;
  NSDate *date1, *date2;

  date1 = [aContainer->message receivedDate];
  date2 = [message receivedDate];
 
  if (date1 == nil || date2 == nil)
    {
      return [self reverseCompareAccordingToNumber: aContainer]; 
    }

  timeInterval = [date1 timeIntervalSinceDate: date2];

  if (timeInterval < 0)
    {
      return NSOrderedAscending;
    }
  else if (timeInterval > 0)
    {
      return NSOrderedDescending;
    }
  else
    {
      return [self reverseCompareAccordingToNumber: aContainer];      
    }
}

- (int) compareAccordingToSender: (Container *) aContainer
{
  NSString *fromString1, *fromString2, *tempString;
  InternetAddress *from1, *from2;
  int result;

  from1 = [message from];
  from2 = [aContainer->message from];

  tempString = [from1 personal];
  if (tempString == nil || [tempString length] == 0)
    {
      fromString1 = [from1 address];
      if (fromString1 == nil)
	fromString1 = @"";
    }
  else
    {
      fromString1 = tempString;
    }


  tempString = [from2 personal];
  if (tempString == nil || [tempString length] == 0)
    {
      fromString2 = [from2 address];
      if (fromString2 == nil)
	fromString2 = @"";
    }
  else
    {
      fromString2 = tempString;
    }

  result = [fromString1 caseInsensitiveCompare: fromString2];
  
  if (result == NSOrderedSame)
    {
      return [self compareAccordingToNumber: aContainer];
    }
  else
    {
      return result;
    }
}

- (int) reverseCompareAccordingToSender: (Container *) aContainer
{
  NSString *fromString1, *fromString2, *tempString;
  InternetAddress *from1, *from2;
  int result;

  from2 = [message from];
  from1 = [aContainer->message from];

  tempString = [from1 personal];
  if (tempString == nil || [tempString length] == 0)
    {
      fromString1 = [from1 address];
      if (fromString1 == nil)
	fromString1 = @"";
    }
  else
    {
      fromString1 = tempString;
    }


  tempString = [from2 personal];
  if (tempString == nil || [tempString length] == 0)
    {
      fromString2 = [from2 address];
      if (fromString2 == nil)
	fromString2 = @"";
    }
  else
    {
      fromString2 = tempString;
    }


  result = [fromString1 caseInsensitiveCompare: fromString2];
  
  if (result == NSOrderedSame)
    {
      return [self reverseCompareAccordingToNumber: aContainer];
    }
  else
    {
      return result;
    }
}

- (int) compareAccordingToSubject: (Container *) aContainer
{
  NSString *subject1, *subject2;
  int result;
  
  subject1 = [message baseSubject];
  subject2 = [aContainer->message baseSubject];
  
  if (subject1 == nil)
    {
      subject1 = @"";
    }
  
  if (subject2 == nil)
    {
      subject2 = @"";
    }
  
  result = [subject1 caseInsensitiveCompare: subject2];

  if (result == NSOrderedSame)
    {
      return [self compareAccordingToNumber: aContainer];      
    }
  else
    {
      return result;
    }
}

- (int) reverseCompareAccordingToSubject: (Container *) aContainer
{
  NSString *subject1, *subject2;
  int result;
  
  subject2 = [message baseSubject];
  subject1 = [aContainer->message baseSubject];

  if (subject1 == nil)
    {
      subject1 = @"";
    }

  if (subject2 == nil)
    {
      subject2 = @"";
    }
  
  result = [subject1 caseInsensitiveCompare: subject2];
  
  if (result == NSOrderedSame)
    {
      return [self compareAccordingToNumber: aContainer];      
    }
  else
    {
      return result;
    }
}

- (int) compareAccordingToSize: (Container *) aContainer
{
  int size1, size2;

  size1 = [message size];
  size2 = [aContainer->message size];

  if (size1 < size2)
    {
      return NSOrderedAscending;
    }
  else if (size1 > size2)
    {
      return NSOrderedDescending;
    }
  else
    {
      return [self compareAccordingToNumber: aContainer];
    }
}

- (int) reverseCompareAccordingToSize: (Container *) aContainer
{
  int size1, size2;

  size2 = [message size];
  size1 = [aContainer->message size];

  if (size1 < size2)
    {
      return NSOrderedAscending;
    }
  else if (size1 > size2)
    {
      return NSOrderedDescending;
    }
  else
    {
      return [self reverseCompareAccordingToNumber: aContainer];      
    }
}

@end
