/*
 *  usercom.C from ObjectProDSP 0.1
 *  Copyright (C) 1994, Mountain Math Software. All rights reserved.
 *  
 *  This file is part of ObjectProDSP, a tool for Digital Signal
 *  Processing design, development and implementation. It is free
 *  software provided you use and distribute it under the terms of
 *  version 2 of the GNU General Public License as published
 *  by the Free Software Foundation. You may NOT distribute it or
 *  works derived from it or code that it generates under ANY
 *  OTHER terms.  In particular NONE of the ObjectProDSP system is
 *  licensed for use under the GNU General Public LIBRARY License.
 *  Mountain Math Software plans to offer a commercial version of
 *  ObjectProDSP for a fee. That version will allow redistribution
 *  of generated code under standard commercial terms.
 *  
 *  This program 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 version 2 of the GNU General
 *  Public License along with this program. See file COPYING. If not
 *  or if you wish information on commercial versions and licensing
 *  write Mountain Math Software, P. O. Box 2124, Saratoga, CA 95070,
 *  USA, or send us e-mail at: support@mtnmath.com.
 *  
 *  You may also obtain the GNU General Public License by writing the
 *  Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 *  USA.  However if you received a copy of this program without the
 *  file COPYING or without a copyright notice attached to all text
 *  files, libraries and executables please inform Mountain Math Software.
 *  
 *  ObjectProDSP is a trademark of Mountain Math Software.
 */

#include <stream.h>
#include <ctype.h>
#include "usercom.h"
#include "cgidbg.h"
#include "grphio.h"
#include "portable.h"
#include "basicio.h"
#include <stdlib.h>

OutCon * Output = 0 ;
OutCon * OutputAppend = 0 ;

WindowBuf::WindowBuf(const WindowBuf&)
{
	exit(55667);
}

int WindowBuf::underflow()
{
	TheLog << "WindowBuf::Underflow***********************\n" ;
	return EOF ;
}


int BasicIO::GetOutputType()
{
	return LastOutput;
}

static ostream * MakeStream(int Index, int append_flag)
{
	return new ostream( new WindowBuf(Index,append_flag)) ;
}

void BasicIO::AddWindow(int Index)
{
	// LogOut << "Adding window = " << Index << "\n" ;
	if (Index < OutputEndOfOutputTypes) DbgError("AddWindow",
		"request to add an existing window");
	if (Index > ArraySize-1) {
/*
 *		LogOut << "Expanding window array to cover: " << Index
 *			<< "\n" ;
 */
		if (Index > 20000) {
			TheLog << "Index = " << Index << "\n" ;
			DbgError( "BasicIO::AddWindow", "window too big");
		}
		int NewSize = ArraySize + (ArraySize >>2) ;
		if (NewSize < Index+3) NewSize += Index + 3 ;
		// if (NewSize <= Index+1) NewSize = Index + 1;
		ostream ** NewStreams = new ostream * [NewSize];
		for (int i = 0; i < ArraySize;i++) NewStreams[i] =
			TheStreams[i] ;
		for (i = ArraySize ; i < NewSize;i++)
			NewStreams[i] = 0;
		ArraySize = NewSize;
		TheStreams = NewStreams ;
	} 
	if (TheStreams[Index]) {
		TheLog << "Index = " << Index << "\n" ;
		DbgError("BasicIO::AddWindow", "window exists");
	}
	if (LastRedirect == RedirectCGI) TheStreams[Index] =
		MakeStream(Index,AppendFlag);
	else TheStreams[Index] = &cout ;
	if (ChannelsInUse <= Index) ChannelsInUse = Index + 1 ;
}



ostream& BasicIO::operator++()
{
	if (!LastOutput) DbgError("BasicIO::()","not redirected");
	LegalStreamIndex(LastOutput,"BasicIO::Operator()");
	return *TheStreams[LastOutput];
}


BasicIO::BasicIO(int append_flag)
{
	// LogOut << "BasicIO::BasicIO, this = " << (void *) this << "\n" ;
	AppendFlag = append_flag ;
	LastRedirect = -1;
	LastOutput = OutputUndefined ;
	ArraySize = OutputEndOfOutputTypes + 8 ;
	TheStreams = new ostream * [ArraySize];
	for (int i = 0; i < ArraySize;i++) TheStreams[i]=0;
	ChannelsInUse = 0;
}

void BasicIO::CleanUp()
{
	if (LastRedirect != RedirectTerminal)
		for (int i = 0 ; i < ChannelsInUse ; i++) delete TheStreams[i];
	delete TheStreams ;
}


BasicIO::~BasicIO()
{
	CleanUp();
}


void BasicIO::LegalStreamIndex(int ix,const char * Where)
{
	if (ix> OutputUndefined && ix < ChannelsInUse) if (TheStreams[ix])
		return ;

/*
 *	LogOut << "ix = " << ix << ", ChannelsInUse = " << ChannelsInUse <<
 *		"\n" ;
 */
 
	DbgError(Where,"bad strstream index");
}

ostream& BasicIO::GetStream(int i)
{
	LegalStreamIndex(i,"GetStream");
	return *(TheStreams[i]) ;
}

ostream& BasicIO::SetWindow(int i)
{
	LegalStreamIndex(i,"BasicIO::SetWindow");
	LastOutput = i;
	// LogOut << "BasicIO Set Window to " << i << "\n" ;
	return (*this).operator++();
}

void OutCon::SetRedirect(RedirectSwitch sw)
{
	Basic->SetRedirect(sw) ;
}

OutCon::OutCon(RedirectSwitch sw, int append_flag)
{
	// LogOut << "OutCon::OutCon\n" ;
	Basic = new BasicIO(append_flag) ;
	Basic->SetRedirect(sw) ;
	AppendFlag = append_flag ;
}

void BasicIO::SetRedirect(RedirectSwitch Redirect)
{
	int i ;
	if (!ChannelsInUse) ChannelsInUse = OutputEndOfOutputTypes ;
	switch(Redirect) {
case RedirectTerminal:
		// LogMsg("Redirect Terminal called");
		if (LastRedirect == RedirectTerminal) return ;
		for (i = OutputUndefined; i < ChannelsInUse ;i++) {
			if (TheStreams[i] || i < OutputEndOfOutputTypes) {
				delete	TheStreams[i] ;
				TheStreams[i] = &cout ;
			}
		}
		break ;
case RedirectCGI:
		// LogMsg("Redirect CGI called");
		if (LastRedirect == RedirectCGI) return ;
		for (i = OutputUndefined; i < ChannelsInUse ;i++)
			if (TheStreams[i] || i < OutputEndOfOutputTypes) 
				TheStreams[i] = MakeStream(i,AppendFlag);
		break ;
default:
		DbgError("OutCon::Redirect","bad switch");
		break ;
	}
	LastRedirect = Redirect ;
}



ostream& OutCon::GetStream(int ix)
{
	// LogOut << "GetStream(" << ix << ")\n" ;
	return Basic->GetStream(ix);
}

void OutCon::SetWindow(int index)
{
	Basic->SetWindow(index);
}


void OutCon::AddWindow(int NewWindowIndex)
{
	Basic->AddWindow(NewWindowIndex) ;
}


int OutCon::GetOutputType()
{
	return Basic->GetOutputType();
}

ostream& OutCon::operator++()
{
	return (*Basic).operator++();
}
 
ostream& OutCon::operator<<(const char* Str)
{
	// LogOut << "OutCon::operator(" << Str << ")\n" ;
	ostream& Return = (*Basic).operator++() << Str;
	// LogOut << "Done\n" ;
	return Return ;
}


ostream& OutCon::operator<<(int a)
{
	return (*Basic).operator++() << a ;
}

ostream& OutCon::operator<<(long n)
{
	return (*Basic).operator++() << n ;
}

ostream& OutCon::operator<<(double d)
{
	return (*Basic).operator++() << d ;
}

ostream& OutputToWindow(int Win)
{
	if (Win) Output->SetWindow(Win);
	return (*Output).operator++();
}

