/* IndentController.m 
 * Copyright (C) 1994 Kurt Werle
 * This is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License, see the file COPYING.
 */

#import "IndentController.h"

@implementation IndentController

- setFileName:(char *)newFileName
{
    myFileName = (char *)malloc (strlen (newFileName) + 1);
    if (myFileName == NULL)
    {
	NXRunAlertPanel (NULL, "You're outta memory!!!\nAborting Program.", "OK", NULL, NULL);
	exit (0);
    }
    strcpy (myFileName, newFileName);
    return self;
}

- initValues
{
    [BlankafterBlock setIntValue:0];
    [BlankafterProcedure setIntValue:0];
    [BlankbeforeBlock setIntValue:0];
    [NewLineafterComma setIntValue:0];
    [LineupCompound setIntValue:0];
    [BlankLineComments setIntValue:1];
    [NestleElses setIntValue:1];
    [LeftJustifyDeclares setIntValue:0];
    [MatchElsetoIf setIntValue:1];
    [FormatCol1Comments setIntValue:1];
    [IndentParameterDeclarations setIntValue:1];
    [JustifyParenthesisSplit setIntValue:1];
    [ConvertSymbols setIntValue:0];
    [SpaceBeforeParens setIntValue:0];
    [SpaceAroundPointers setIntValue:0];
    [ProcedureNameCol1 setIntValue:1];
    [LineComments setIntValue:1];
    [DeleteExtraBlanks setIntValue:0];
    [VerboseMode setIntValue:0];

    [CommentCodeCol setIntValue:33];
    [CommentDeclarationCol setIntValue:33];
    [ContinuationIndent setIntValue:0];
    [IndentCaseLabels setFloatValue:0.0];
    [NegativeIndentComments setIntValue:0];
    [IndentVariableDeclarations setIntValue:16];
    [SpaceperIndent setIntValue:8];
    [MaxLineLength setIntValue:78];
    [MaxCommentLineLength setIntValue:78];
    [TabStopWidth setIntValue:8];
    return self;
}

- (const char *)OptionString
{
    char            allTypeDefText[2048];

    /* So Now we get Ugly... */

    [typedefText getSubstring:allTypeDefText start:0 length:[typedefText textLength] + 1];
    sprintf (indentCodes, "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s -c%d -cd%d -ci%d -cli%f -d%d -di%d -i%d -l%d -lc%d -ts%d %s",
	     [BlankafterBlock intValue] ? "-bad" : "-nbad",
	     [BlankafterProcedure intValue] ? "-bap" : "-nbap",
	     [BlankbeforeBlock intValue] ? "-bbb" : "-nbbb",
	     [NewLineafterComma intValue] ? "-bc" : "-nbc",
	     [LineupCompound intValue] ? "-br" : "-bl",
	     [BlankLineComments intValue] ? "-cdb" : "-ncdb",
	     [NestleElses intValue] ? "-ce" : "-nce",
	     [LeftJustifyDeclares intValue] ? "-dj" : "-ndj",
	     [MatchElsetoIf intValue] ? "-ei" : "-nei",
	     [FormatCol1Comments intValue] ? "-fc1" : "-nfc1",
	     [IndentParameterDeclarations intValue] ? "-ip" : "-nip",
	     [JustifyParenthesisSplit intValue] ? "-lp" : "-nlp",
	     [ConvertSymbols intValue] ? "-osa" : "-nosa",
	     [SpaceBeforeParens intValue] ? "-pcs" : "-npcs",
	     [SpaceAroundPointers intValue] ? "-ps" : "-nps",
	     [ProcedureNameCol1 intValue] ? "-psl" : "-npsl",
	     [LineComments intValue] ? "-sc" : "-nsc",
	     [DeleteExtraBlanks intValue] ? "-sob" : "-nsob",
	     [VerboseMode intValue] ? "-v" : "-nv",

	     [CommentCodeCol intValue],
	     [CommentDeclarationCol intValue],
	     [ContinuationIndent intValue],
	     [IndentCaseLabels floatValue],
	     [NegativeIndentComments intValue],
	     [IndentVariableDeclarations intValue],
	     [SpaceperIndent intValue],
	     [MaxLineLength intValue],
	     [MaxCommentLineLength intValue],
	     [TabStopWidth intValue],
	     allTypeDefText
	);

    return indentCodes;
}

#define MAXTOKENLENGTH 80	/* If you have tokens over 80 chars */
#define FSCANF_FORMAT_STRING "%79s"	/* You deserve what you get. */

- (void)parseIndentFile:(char *)indentFileName
{
    char            indentToken[MAXTOKENLENGTH], sometypedefText[MAXTOKENLENGTH];
    FILE           *indentFile;
    int             tempint;
    float           tempfloat;

    indentFile = fopen (indentFileName, "rt");
    [self setFileName:indentFileName];
    strcpy (myFileName, indentFileName);

    [typedefText selectAll:self];
    [typedefText replaceSel:""];

    while (fscanf (indentFile, FSCANF_FORMAT_STRING, indentToken) > 0)
    {
	/* We only need to test for the 'non-default' case */
	if (strstr (indentToken, "-bad"))
	    [BlankafterBlock setIntValue:1];
	if (strstr (indentToken, "-bap"))
	    [BlankafterProcedure setIntValue:1];
	if (strstr (indentToken, "-bbb"))
	    [BlankbeforeBlock setIntValue:1];
	if (strstr (indentToken, "-bc"))
	    [NewLineafterComma setIntValue:1];
	if (strstr (indentToken, "-bl"))
	    [LineupCompound setIntValue:0];
	if (strstr (indentToken, "-ncdb"))
	    [BlankLineComments setIntValue:0];
	if (strstr (indentToken, "-nce"))
	    [NestleElses setIntValue:0];
	if (strstr (indentToken, "-dj"))
	    [LeftJustifyDeclares setIntValue:1];
	if (strstr (indentToken, "-nei"))
	    [MatchElsetoIf setIntValue:0];
	if (strstr (indentToken, "-nfc1"))
	    [FormatCol1Comments setIntValue:0];
	if (strstr (indentToken, "-nip"))
	    [IndentParameterDeclarations setIntValue:0];
	if (strstr (indentToken, "-nlp"))
	    [JustifyParenthesisSplit setIntValue:0];
	if (strstr (indentToken, "-osa"))
	    [ConvertSymbols setIntValue:1];
	if (strstr (indentToken, "-pcs"))
	    [SpaceBeforeParens setIntValue:1];
	if (strstr (indentToken, "-ps"))
	    [SpaceAroundPointers setIntValue:1];
	if (strstr (indentToken, "-npsl"))
	    [ProcedureNameCol1 setIntValue:0];
	if (strstr (indentToken, "-nsc"))
	    [LineComments setIntValue:0];
	if (strstr (indentToken, "-sob"))
	    [DeleteExtraBlanks setIntValue:1];
	if (strstr (indentToken, "-v"))
	    [VerboseMode setIntValue:1];

	if (sscanf (indentToken, "-c%d", &tempint))
	    [CommentCodeCol setIntValue:tempint];
	if (sscanf (indentToken, "-cd%d", &tempint))
	    [CommentDeclarationCol setIntValue:tempint];
	if (sscanf (indentToken, "-ci%d", &tempint))
	    [ContinuationIndent setIntValue:tempint];
	if (sscanf (indentToken, "-cli%f", &tempfloat))
	    [IndentCaseLabels setFloatValue:tempfloat];
	if (sscanf (indentToken, "-d%d", &tempint))
	    [NegativeIndentComments setIntValue:tempint];
	if (sscanf (indentToken, "-di%d", &tempint))
	    [IndentVariableDeclarations setIntValue:tempint];
	if (sscanf (indentToken, "-i%d", &tempint))
	    [SpaceperIndent setIntValue:tempint];
	if (sscanf (indentToken, "-l%d", &tempint))
	    [MaxLineLength setIntValue:tempint];
	if (sscanf (indentToken, "-lc%d", &tempint))
	    [MaxCommentLineLength setIntValue:tempint];
	if (sscanf (indentToken, "-ts%d", &tempint))
	    [TabStopWidth intValue];

	if (sscanf (indentToken, "-T%s", sometypedefText))
	{
	    [typedefText setSel:0 :0];
	    [typedefText replaceSel:" "];
	    [typedefText setSel:0 :0];
	    [typedefText replaceSel:indentToken];
	}
    }
}

- appDidInit:sender
{

    [self setFileName:"./.indent.pro"];
    myCodeBlock = NXOpenMemory (NULL, 0, NX_READWRITE);
    [myCodeScrollView writeText:myCodeBlock];
    NXSeek (myCodeBlock, 0, NX_FROMSTART);
    myFileName = NULL;
    return self;
}

- (BOOL)appAcceptsAnotherFile:sender
{
    return YES;
}

- (int)app:sender openFile:(const char *)filename type:(const char *)aType;
{
    [self parseIndentFile:filename];
    return YES;
}

- loadInfo:sender
{
    [NXApp loadNibSection:"info.nib" owner:self withNames:NO];
    return self;
}

- NewFile:sender
{
    [self initValues];
    return self;
}

- LoadFile:sender
{
    id              myopenpanel;
    const char     *const types[2] = {"pro", NULL};

    myopenpanel = [OpenPanel new];

    [myopenpanel allowMultipleFiles:FALSE];
    if (NX_OKTAG == [myopenpanel runModalForDirectory:"." file:".indent.pro" types:types])
    {
	[self initValues];

	[self parseIndentFile:[myopenpanel filename]];
    }
    return self;
}

- ProcessCode:sender
{
    char            systemLine[2048];
    NXStream       *tempCodeFileStream;
    int             tempCodeFile;

    /*
       This is totally bogus.  Why do I have to open this file TWICE?!? There
       Should Be a command NXOpenMyDamnFile(const char *filename, int flags)! 
    */
    tempCodeFile = open (".indent.code.c", O_WRONLY | O_CREAT, 0777);

#ifdef DEBUG
    if (tempCodeFile != -1)
	printf ("opened %d\n", tempCodeFile);
    else
	perror ("bummer");
#endif

    tempCodeFileStream = NXOpenFile (tempCodeFile, NX_WRITEONLY);
    printf ("openedstream %p\n", tempCodeFileStream);

    [myCodeScrollView writeText:tempCodeFileStream];
    /*
       And while I'm ranting, can I just get a copy of the Text text so I can
       do my own fopen/fprintf? 
    */

    NXClose (tempCodeFileStream);
    close (tempCodeFile);

    sprintf (systemLine, "indent -npro %s .indent.code.c",[self OptionString]);

#ifdef DEBUG
    printf ("%s\n", systemLine);
#endif

    /*
       I wanted to do this using a pipe, and avoid the whole temporary file
       thing, but pipes look real ugly.  Is there no easy way to say
       'openmypipe (systemLine, &writefd, &readfd)? 
    */
    system (systemLine);

    tempCodeFile = open (".indent.code.c", O_RDONLY, 777);
    tempCodeFileStream = NXOpenFile (tempCodeFile, NX_READONLY);
    [myCodeScrollView readText:tempCodeFileStream];
    NXClose (tempCodeFileStream);

    unlink (".indent.code.c");
    unlink (".indent.code.c.BAK");

    return self;
}

- ResetCode:sender
{
    [myCodeScrollView readText:myCodeBlock];
    NXSeek (myCodeBlock, 0, NX_FROMSTART);
    return self;
}

- SaveFile:sender
{
    FILE           *mySaveFile;

    if (myFileName == NULL)
    {
	myFileName = "./.indent.pro";
	return[self SaveFileAs:self];
    }

    if (!access (myFileName, F_OK))	/* Rename the old file .BAK */
    {
	char           *newFileName = (char *)malloc (strlen (myFileName) + 5);

	if (newFileName == NULL)
	{
	    NXRunAlertPanel (NULL, "You're outta memory!!!\nAborting Save.", "OK", NULL, NULL);
	    return self;
	}

	strcpy (newFileName, myFileName);
	strcat (newFileName, ".BAK");
	unlink (newFileName);	/* Remove old .BAK file if it exists */
	if (0 != rename (myFileName, newFileName))
	{
	    if (NX_ALERTDEFAULT != NXRunAlertPanel (NULL, "Couldn't make backup.\nSave over file?", "OK", "Don't Hose me!", NULL))
	    {
		free (newFileName);
		return self;
	    }
	}
	free (newFileName);
    }

    mySaveFile = fopen (myFileName, "wt");
    if (!mySaveFile)
    {
	NXRunAlertPanel (NULL, "Couldn't open save file.\nAborting Save?", "OK", NULL, NULL);
	return self;
    }
    if (0 != fprintf (mySaveFile, "%s\n",[self OptionString]))
	NXRunAlertPanel (NULL, "Save failed.\nCouldn't write to opened file.", "OK", NULL, NULL);
    fclose (mySaveFile);
    return self;
}

- SaveFileAs:sender
{
    id              mySavePanel;
    char           *saveFilePath, *saveFileName;

    if (myFileName == NULL)
    {
	[self setFileName:"./.indent.pro"];
    }

    saveFilePath = (char *)malloc (strlen (myFileName) + 1);
    if (saveFilePath == NULL)
    {
	NXRunAlertPanel (NULL, "You're outta memory!!!\nAborting Save.", "OK", NULL, NULL);
	return self;
    }
    strcpy (saveFilePath, myFileName);
    if (NULL == (saveFileName = strchr (saveFilePath, '/')))
    {
	saveFileName = saveFilePath;
    }
    else
    {
	*saveFileName = '\0';
	saveFileName++;
    }

    mySavePanel = [SavePanel new];

    if (NX_OKTAG == [mySavePanel runModalForDirectory:saveFilePath file:saveFileName])
    {
	[self setFileName:[mySavePanel filename]];
	free (saveFilePath);
	return[self SaveFile:self];
    }

    free (saveFilePath);
    return self;
}

- free
{				/* I wonder why this is never called... */
    if (myFileName != NULL)
    {
	free (myFileName);
    }
    NXCloseMemory (myCodeBlock, NX_TRUNCATEBUFFER);
    return[super free];
}

@end
