/*
   GNUstep ProjectCenter - http://www.gnustep.org

   Copyright (C) 2002-2004 Free Software Foundation

   Authors: Philippe C.D. Robert
            Serg Stoyan

   This file is part of GNUstep.

   This application 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 application 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
   Library General Public License for more details.

   You should have received a copy of the GNU General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/

#include "PCDefines.h"
#include "PCProject.h"
#include "PCMakefileFactory.h"

#define COMMENT_HEADERS      @"\n\n#\n# Header files\n#\n"
#define COMMENT_RESOURCES    @"\n\n#\n# Resource files\n#\n"
#define COMMENT_CLASSES      @"\n\n#\n# Class files\n#\n"
#define COMMENT_CFILES       @"\n\n#\n# C files\n#\n"
#define COMMENT_SUBPROJECTS  @"\n\n#\n# Subprojects\n#\n"
#define COMMENT_APP          @"\n\n#\n# Main application\n#\n"
#define COMMENT_LIBRARIES    @"\n\n#\n# Additional libraries\n#\n"
#define COMMENT_BUNDLE       @"\n\n#\n# Bundle\n#\n"
#define COMMENT_LIBRARY      @"\n\n#\n# Library\n#\n"
#define COMMENT_TOOL         @"\n\n#\n# Tool\n#\n"
#define COMMENT_LOCALIZATION @"\n\n#\n# Localization\n#\n"

@implementation PCMakefileFactory

static PCMakefileFactory *_factory = nil;

+ (PCMakefileFactory *)sharedFactory
{
  static BOOL isInitialised = NO;

  if( isInitialised == NO )
    {
      _factory = [[PCMakefileFactory alloc] init];

      isInitialised = YES;
    }

  return _factory;
}

- (void)createMakefileForProject:(NSString *)prName
{
  NSAssert( prName, @"No project name given!");

  AUTORELEASE( mfile );
  mfile = [[NSMutableString alloc] init];

  AUTORELEASE( pnme );
  pnme = [prName copy];

  [mfile appendString:@"#\n"];
  [mfile appendString:@"# GNUmakefile - Generated by ProjectCenter\n"];
  [mfile appendString:@"#\n"];
  
  [mfile appendString:@"\ninclude $(GNUSTEP_MAKEFILES)/common.make\n"];
}

- (BOOL)createPreambleForProject:(PCProject *)project
{
  NSMutableString *mfp = [[NSMutableString alloc] init];
  NSString        *mfl = nil;
  NSArray         *array = nil;
  NSDictionary    *projectDict = [project projectDict];
  NSString        *projectPath = [project projectPath];

  // Create the new file
  [mfp appendString:@"#\n"];
  [mfp appendString:@"# GNUmakefile.preamble - Generated by ProjectCenter\n"];
  [mfp appendString:@"#\n\n"];

  // Preprocessor flags
  [mfp appendString:@"# Additional flags to pass to the preprocessor\n"];
  [mfp appendString:
    [NSString stringWithFormat:@"ADDITIONAL_CPPFLAGS += %@\n\n", 
     [projectDict objectForKey:PCPreprocessorOptions]]];

  // Objective C compiler flags
  [mfp appendString:@"# Additional flags to pass to Objective C compiler\n"];
  [mfp appendString:
    [NSString stringWithFormat:@"ADDITIONAL_OBJCFLAGS += %@\n\n",
     [projectDict objectForKey:PCObjCCompilerOptions]]];
    
  // C compiler flags
  [mfp appendString:@"# Additional flags to pass to C compiler\n"];
  [mfp appendString:
    [NSString stringWithFormat:@"ADDITIONAL_CFLAGS += %@\n\n",
     [projectDict objectForKey:PCCompilerOptions]]];
		     
  // Linker flags
  [mfp appendString:@"# Additional flags to pass to the linker\n"];
  [mfp appendString:
    [NSString stringWithFormat:@"ADDITIONAL_LDFLAGS += %@ ",
     [projectDict objectForKey:PCLinkerOptions]]];
  array = [projectDict objectForKey:PCLibraries];
  if (array && [array count])
    {
      NSString     *tmp;
      NSEnumerator *enumerator = [array objectEnumerator];
      
      while ((tmp = [enumerator nextObject]))
        {
          if (![tmp isEqualToString:@"gnustep-base"] &&
              ![tmp isEqualToString:@"gnustep-gui"])
            {
              [mfp appendString:[NSString stringWithFormat:@"-l%@ ",tmp]];
            }
        }
    }
  [mfp appendString:@"\n\n"];

  // Directories where to search headers
  [mfp appendString:
    @"# Additional include directories the compiler should search\n"];
  [mfp appendString:@"ADDITIONAL_INCLUDE_DIRS += "];
  array = [projectDict objectForKey:PCSearchHeaders];
  if (array && [array count])
    {
      NSString     *tmp;
      NSEnumerator *enumerator = [array objectEnumerator];

      while ((tmp = [enumerator nextObject])) 
	{
	  [mfp appendString:[NSString stringWithFormat:@"-I%@ ",tmp]];
	}
    }
  [mfp appendString:@"\n\n"];
  
  // Directories where to search libraries
  [mfp appendString:
    @"# Additional library directories the linker should search\n"];
  [mfp appendString:@"ADDITIONAL_LIB_DIRS += "];
  array = [projectDict objectForKey:PCSearchLibs];
  if (array && [array count])
    {
      NSString     *tmp;
      NSEnumerator *enumerator = [array objectEnumerator];

      while ((tmp = [enumerator nextObject])) 
	{
	  [mfp appendString:[NSString stringWithFormat:@"-L%@ ",tmp]];
	}
    }
  [mfp appendString:@"\n\n"];

//  [mfp appendString:[projectDict objectForKey:PCLibraries]];

  // Write the new file to disc!
  mfl = [projectPath stringByAppendingPathComponent:@"GNUmakefile.preamble"];
  if ([mfp writeToFile:mfl atomically:YES]) 
    {
      return YES;
    }

  return NO;
}

- (BOOL)createPostambleForProject:(PCProject *)project
{
  NSBundle      *bundle = nil;
  NSString      *template = nil;
  NSString      *postamble = nil;
  NSFileManager *fm = [NSFileManager defaultManager];
  
  bundle = [NSBundle bundleForClass:[self class]];
  template = [bundle pathForResource:@"postamble" ofType:@"template"];
  postamble = [[project projectPath] 
    stringByAppendingPathComponent:@"GNUmakefile.postamble"];

  return [fm copyPath:template toPath:postamble handler:nil];
}

- (void)appendString:(NSString *)aString
{
  NSAssert( mfile, @"No valid makefile available!");
  NSAssert( aString, @"No valid string!");

  [mfile appendString:aString];
}

- (void)appendHeaders:(NSArray *)array
{
  [self appendHeaders:array forTarget:pnme];
}

- (void)appendHeaders:(NSArray *)array forTarget:(NSString *)target
{
  [self appendString:COMMENT_HEADERS];
  [self appendString:
    [NSString stringWithFormat:@"%@_HEADER_FILES = \\\n", target]];

  [self appendString:[array componentsJoinedByString:@" \\\n"]];
}

- (void)appendClasses:(NSArray *)array
{
  [self appendClasses:array forTarget:pnme];
}

- (void)appendClasses:(NSArray *)array forTarget:(NSString *)target
{
  [self appendString:COMMENT_CLASSES];
  [self appendString:
    [NSString stringWithFormat:@"%@_OBJC_FILES = \\\n",target]];

  [self appendString:[array componentsJoinedByString:@" \\\n"]];
}

- (void)appendOtherSources:(NSArray *)array
{
  [self appendOtherSources: array forTarget: pnme];
}

- (void)appendOtherSources:(NSArray *)array forTarget: (NSString *)target
{
  NSMutableArray *marray = nil;
  NSEnumerator   *oenum;
  NSString       *file;
  
  [self appendString:COMMENT_CFILES];
  [self appendString:[NSString stringWithFormat:@"%@_C_FILES = ", target]];
  if ( array == nil || [array count] == 0)
    return;
  
  /* Other Sources can have both m files and c files (possibly others?).  */
  oenum = [array objectEnumerator];
  while ((file = [oenum nextObject]))
    {
      if ([file hasSuffix: @".m"])
	{
	  if (marray == nil)
	    marray = [NSMutableArray arrayWithCapacity: 2];
	  [marray addObject: file];
	}
      else /* if ([f hasSuffix: @".c"]) */
	{
	  [self appendString:[NSString stringWithFormat:@"\\\n%@ ",file]];
	}
    }

  [self appendString: @"\n\n"];
  [self appendString:[NSString stringWithFormat:@"%@_OBJC_FILES += ",pnme]];
  if ( marray )
    {
      NSString     *file;
      NSEnumerator *enumerator = [marray objectEnumerator];
	
      while ( (file = [enumerator nextObject]) ) 
	{
	  [self appendString:[NSString stringWithFormat:@"\\\n%@ ", file]];
	}
    }
}

- (void)appendResources
{
  [self appendString:COMMENT_RESOURCES];
  [self appendString:
    [NSString stringWithFormat:@"%@_RESOURCE_FILES = ",pnme]];
}

- (void)appendResourceItems:(NSArray *)array
{
  if ([array count] <= 0)
    {
      return;
    }

  [self appendString:@"\\\n"];
  [self appendString:[array componentsJoinedByString:@" \\\n"]];
}

- (void)appendLocalization
{
  [self appendString:COMMENT_LOCALIZATION];
}

- (void)appendSubprojects:(NSArray*)array
{
  [self appendString:COMMENT_SUBPROJECTS];
  [self appendString:@"SUBPROJECTS = "];

  if (array && [array count]) 
    {
      NSString     *tmp;
      NSEnumerator *enumerator = [array objectEnumerator];

      while ((tmp = [enumerator nextObject]))
	{
	  tmp = [tmp stringByAppendingPathExtension:@"subproj"];
	  [self appendString:[NSString stringWithFormat:@"\\\n%@ ",tmp]];
	}
    }
}

- (NSData *)encodedMakefile
{
  NSAssert( mfile, @"No valid makefile available!");

  return [mfile dataUsingEncoding:[NSString defaultCStringEncoding]];
}

@end

