/* UIxContactFoldersView.m - this file is part of SOGo
 *
 * Copyright (C) 2006 Inverse groupe conseil
 *
 * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
 *
 * This file 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, or (at your option)
 * any later version.
 *
 * This file 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; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#import <Foundation/NSString.h>

#import <NGObjWeb/NSException+HTTP.h>
#import <NGObjWeb/SoObject.h>
#import <NGObjWeb/WOResponse.h>
#import <NGObjWeb/WOContext.h>

#import <GDLContentStore/GCSFolder.h>
#import <GDLContentStore/GCSFolderManager.h>

#import <SoObjects/SOGo/SOGoUser.h>
#import <SoObjects/SOGo/NSString+Utilities.h>
#import <SoObjects/Contacts/SOGoContactFolders.h>
#import <SoObjects/Contacts/SOGoContactFolder.h>
#import <SoObjects/Contacts/SOGoContactGCSFolder.h>
#import <SoObjects/Contacts/SOGoContactLDAPFolder.h>

#import "common.h"

#import "UIxContactFoldersView.h"

@implementation UIxContactFoldersView

- (id) _selectActionForApplication: (NSString *) actionName
{
  SOGoContactFolders *folders;
  NSString *url, *action;
  WORequest *request;

  folders = [self clientObject];
  action = [NSString stringWithFormat: @"../%@/%@",
                     [folders defaultSourceName],
                     actionName];

  request = [[self context] request];

  url = [[request uri] composeURLWithAction: action
                       parameters: [self queryParameters]
                       andHash: NO];

  return [self redirectToLocation: url];
}

- (id) defaultAction
{
  return [self _selectActionForApplication: @"view"];
}

- (id) newAction
{
  return [self _selectActionForApplication: @"new"];
}

- (id <WOActionResults>) newAbAction
{
  id <WOActionResults> response;
  NSString *name;

  name = [self queryParameterForKey: @"name"];
  if ([name length] > 0)
    response = [[self clientObject] newFolderWithName: name];
  else
    response = [NSException exceptionWithHTTPStatus: 400
                            reason: @"The name is missing"];
  
  return response;
}

- (id) selectForMailerAction
{
  return [self _selectActionForApplication: @"mailer-contacts"];
}

- (NSArray *) _searchResults: (NSString *) contact
	     ldapFoldersOnly: (BOOL) ldapFoldersOnly
{
  NSMutableArray *results;
  SOGoContactFolders *topFolder;
  NSEnumerator *sogoContactFolders;
  id <SOGoContactFolder> currentFolder;

  results = [NSMutableArray new];
  [results autorelease];

  topFolder = [self clientObject];
  sogoContactFolders = [[topFolder contactFolders] objectEnumerator];
  currentFolder = [sogoContactFolders nextObject];
  while (currentFolder)
    {
      if (!ldapFoldersOnly
	  || [currentFolder isKindOfClass: [SOGoContactLDAPFolder class]])
	[results addObjectsFromArray: [currentFolder
					lookupContactsWithFilter: contact
					sortBy: @"cn"
					ordering: NSOrderedAscending]];
      currentFolder = [sogoContactFolders nextObject];
    }
  [topFolder release];

  return results;
}

- (NSString *) _emailForResult: (NSDictionary *) result
{
  NSMutableString *email;
  NSString *name, *mail;

  email = [NSMutableString string];
  name = [result objectForKey: @"displayName"];
  if (![name length])
    name = [result objectForKey: @"cn"];
  mail = [result objectForKey: @"mail"];
  if ([name length])
    [email appendFormat: @"%@ <%@>", name, mail];
  else
    [email appendString: mail];

  return email;
}

- (NSDictionary *) _nextResultWithUid: (NSEnumerator *) results
{
  NSDictionary *result, *possibleResult;

  result = nil;
  possibleResult = [results nextObject];
  while (possibleResult && !result)
    if ([[possibleResult objectForKey: @"c_uid"] length])
      result = possibleResult;
    else
      possibleResult = [results nextObject];

  return result;
}

- (WOResponse *) _responseForResults: (NSArray *) results
{
  WOResponse *response;
  NSString *email, *responseString, *uid;
  NSDictionary *result;

  response = [context response];

  if ([results count])
    {
      result = [self _nextResultWithUid: [results objectEnumerator]];
      if (!result)
        result = [results objectAtIndex: 0];
      email = [self _emailForResult: result];
      uid = [result objectForKey: @"c_uid"];
      if ([uid length] == 0)
        uid = @"";
      responseString = [NSString stringWithFormat: @"%@:%@",
                                 uid, email];
      [response setStatus: 200];
      [response setHeader: @"text/plain; charset=iso-8859-1"
                forKey: @"Content-Type"];
      [response appendContentString: responseString];
    }
  else
    [response setStatus: 404];

  return response;
}

- (id <WOActionResults>) contactSearchAction
{
  NSString *contact;
  id <WOActionResults> result;
  BOOL ldapFoldersOnly;

  contact = [self queryParameterForKey: @"search"];
  ldapFoldersOnly = [[self queryParameterForKey: @"ldap-only"] boolValue];
  if ([contact length] > 0)
    result
      = [self _responseForResults: [self _searchResults: contact
					 ldapFoldersOnly: ldapFoldersOnly]];
  else
    result = [NSException exceptionWithHTTPStatus: 400
                          reason: @"missing 'search' parameter"];
  
  return result;
}

- (NSArray *) _gcsFoldersFromFolder: (SOGoContactFolders *) contactFolders
{
  NSMutableArray *gcsFolders;
  NSEnumerator *contactSubfolders;
  SOGoContactGCSFolder *currentContactFolder;
  NSString *folderName, *displayName;
  NSMutableDictionary *currentDictionary;

  gcsFolders = [NSMutableArray new];
  [gcsFolders autorelease];

  contactSubfolders = [[contactFolders contactFolders] objectEnumerator];
  currentContactFolder = [contactSubfolders nextObject];
  while (currentContactFolder)
    {
      if ([currentContactFolder
	    isKindOfClass: [SOGoContactGCSFolder class]])
	{
	  folderName = [NSString stringWithFormat: @"/Contacts/%@",
				 [currentContactFolder nameInContainer]];
	  currentDictionary = [NSMutableDictionary new];
	  [currentDictionary autorelease];
	  displayName = [[currentContactFolder ocsFolder] folderName];
	  [currentDictionary setObject: displayName forKey: @"displayName"];
	  [currentDictionary setObject: folderName forKey: @"name"];
	  [currentDictionary setObject: @"contact" forKey: @"type"];
	  [gcsFolders addObject: currentDictionary];
	}
      currentContactFolder = [contactSubfolders nextObject];
    }

  return gcsFolders;
}

- (NSArray *) _foldersForUID: (NSString *) uid
		      ofType: (NSString *) folderType
{
  NSObject *topFolder, *userFolder;
  SOGoContactFolders *contactFolders;
  NSMutableArray *folders;
  NSMutableDictionary *currentDictionary;

  folders = [NSMutableArray new];
  [folders autorelease];

  topFolder = [[[self clientObject] container] container];
  userFolder = [topFolder lookupName: uid inContext: context acquire: NO];

  /* FIXME: should be moved in the SOGo* classes. Maybe by having a SOGoFolderManager. */
#warning this might need adjustments whenever we permit multiple calendar folders per-user
  if ([folderType length] == 0 || [folderType isEqualToString: @"calendar"])
    {
      currentDictionary = [NSMutableDictionary new];
      [currentDictionary autorelease];
      [currentDictionary setObject: [self labelForKey: @"Calendar"]
			 forKey: @"displayName"];
      [currentDictionary setObject: @"/Calendar" forKey: @"name"];
      [currentDictionary setObject: @"calendar" forKey: @"type"];
      [folders addObject: currentDictionary];
    }
  if ([folderType length] == 0 || [folderType isEqualToString: @"contact"])
    {
      contactFolders = [userFolder lookupName: @"Contacts"
				   inContext: context acquire: NO];
      [folders
	addObjectsFromArray: [self _gcsFoldersFromFolder: contactFolders]];
    }

  return folders;
}

- (NSString *) _foldersStringForFolders: (NSEnumerator *) folders
{
  NSMutableString *foldersString;
  NSDictionary *currentFolder;

  foldersString = [NSMutableString new];
  [foldersString autorelease];

  currentFolder = [folders nextObject];
  while (currentFolder)
    {
      [foldersString appendFormat: @";%@:%@:%@",
		     [currentFolder objectForKey: @"displayName"],
		     [currentFolder objectForKey: @"name"],
		     [currentFolder objectForKey: @"type"]];
      currentFolder = [folders nextObject];
    }

  return foldersString;
}

- (WOResponse *) _foldersResponseForResults: (NSArray *) results
				   withType: (NSString *) folderType
{
  WOResponse *response;
  NSString *uid, *foldersString;
  NSMutableString *responseString;
  NSDictionary *result;
  NSEnumerator *resultsEnum;
  NSArray *folders;

  response = [context response];

  if ([results count])
    {
      [response setStatus: 200];
      [response setHeader: @"text/plain; charset=iso-8859-1"
                forKey: @"Content-Type"];

      responseString = [NSMutableString new];
      resultsEnum = [results objectEnumerator];
      result = [resultsEnum nextObject];
      while (result)
	{
	  uid = [result objectForKey: @"c_uid"];
	  folders = [self _foldersForUID: uid ofType: folderType];
	  foldersString
	    = [self _foldersStringForFolders: [folders objectEnumerator]];
	  [responseString appendFormat: @"%@:%@%@\n",
			  uid, [self _emailForResult: result], foldersString];
	  result = [resultsEnum nextObject];
	}
      [response appendContentString: responseString];
      [responseString release];
    }
  else
    [response setStatus: 404];

  return response;
}

- (id <WOActionResults>) foldersSearchAction
{
  NSString *contact, *folderType;
  id <WOActionResults> result;
  BOOL ldapOnly;

  contact = [self queryParameterForKey: @"search"];
  if ([contact length] > 0)
    {
      ldapOnly = [[self queryParameterForKey: @"ldap-only"] boolValue];
      folderType = [self queryParameterForKey: @"type"];
      result = [self _foldersResponseForResults:
		       [self _searchResults: contact
			     ldapFoldersOnly: ldapOnly]
		     withType: folderType];
    }
  else
    result = [NSException exceptionWithHTTPStatus: 400
                          reason: @"missing 'search' parameter"];

  return result;
}

- (SOGoContactGCSFolder *) contactFolderForUID: (NSString *) uid
{
  SOGoFolder *upperContainer;
  SOGoUserFolder *userFolder;
  SOGoContactFolders *contactFolders;
  SOGoContactGCSFolder *contactFolder;
  SoSecurityManager *securityManager;

  upperContainer = [[[self clientObject] container] container];
  userFolder = [SOGoUserFolder objectWithName: uid
                               inContainer: upperContainer];
  contactFolders = [SOGoContactFolders objectWithName: @"Contacts"
                                       inContainer: userFolder];
  contactFolder = [SOGoContactGCSFolder objectWithName: @"personal"
                                        inContainer: contactFolders];
  [contactFolder
    setOCSPath: [NSString stringWithFormat: @"/Users/%@/Contacts/personal", uid]];
  [contactFolder setOwner: uid];

  securityManager = [SoSecurityManager sharedSecurityManager];

  return (([securityManager validatePermission: SoPerm_AccessContentsInformation
                            onObject: contactFolder
                            inContext: context] == nil)
          ? contactFolder : nil);
}

@end
