// Copyright 2000
// College of Computer Science
// Northeastern University Boston MA 02115

// This software may be used for educational purposes as long as this copyright
// notice is retained at the top of all files

// Should this software be modified, the words "Modified from Original" must be
// included as a comment below this notice

// All publication rights are retained.  This software or its documentation may
// not be published in any media either in whole or in part.

///////////////////////////////////////////////////////////////////////////////

// RGB.cpp

///////////////////////////////////////////////////////////////////////////////

#include "CoreTools.h"				// needed for core tools compile in Win32

#include "RGB.h"
#include "IOTools.h"

using namespace std;


RGBdata& RGBdata::Request(			// respond-or-default
	const string&		prompt,		// prompt to user
	const RGBdata&		answer		// default answer
) {
	string stringanswer(answer.ToString());
	string stringresponse;
	RGBdata response;
	
	while (true) {		
		RequestString(prompt, stringanswer, stringresponse);
		
		if (InputError() || stringresponse.length() == 0)
			return Set(answer);
		
		int start = 0;
		int next  =	0;
		int error = NoError;
		
		response.FromString(stringresponse, start, next, error);
		
		if (!error)
			return Set(response);
		
		ErrorPrint(stringresponse, next, error);
	}
}
	
	
RGBdata& RGBdata::Request(			// mandatory response
	const string&		prompt		// prompt to user
) {
	string stringresponse;
	RGBdata response;

	while (true) {		
		RequestString(prompt, stringresponse);
		
		if (InputError())
			return Set();
		
		int start = 0;
		int next  =	0;
		int error = NoError;
		
		if (stringresponse.length()) {
			response.FromString(stringresponse, start, next, error);
			
			if (!error)
				return Set(response);
		}
		else
			error = NoDataError;
		
		ErrorPrint(stringresponse, next, error);
	}
}
	
	
bool RGBdata::Reading(				// respond-or-decline
	const string&		prompt		// prompt to user
) {
	string stringresponse;
	RGBdata response;
	
	while (true) {		
		RequestString(prompt, stringresponse);
		
		if (InputError() || stringresponse.length() == 0)
			return false;
		
		int start = 0;
		int next  =	0;
		int error = NoError;
		
		response.FromString(stringresponse, start, next, error);
		
		if (!error) {
			Set(response);
			return true;
		};
		
		ErrorPrint(stringresponse, next, error);
	}
}
	
	
RGBdata& RGBdata::FromString(
	const string&	source,			// string to read
	int				start,			// start position to read
	int&			next,			// next  position to read
	int&			error			// string IO error code
) {
	// find size
	int size = source.length();
	
	// check start
	if (start < 0)
		start = 0;
	
	if (start >= size) {
		next  = size;
		error = NoDataError;
		return *this;
	}
	
	// initialize error
	error = NoError;
	
	// process string via const char* pointer
	const char* temp = source.c_str() + start;
	const char* stop = temp;
	
	// use the C string version of FromString
	FromString(temp, stop, error);
	
	// compute next index
	next = start + (stop - temp);
	
	return *this;
}
	
	
RGBdata& RGBdata::FromString(
	const char*		start,			// start position to read
	const char*&	next,			// next  position to read
	int&			error			// string IO error code
) {
	int count = 0;					// component number
	const int components = 3;		// number of components

	short number;					// temporary number variable
	RGBdata result;					// temporary result variable

	// prepare for initial scan
	SkipSpace(start);
	next  = start;
	error = NoError;
	
	while (count < components) {
		// update component count
		count++;

		// update start to read next number
		start = next;

		// read next number
		number = StringToShort(start, next, error);

		// check for error on read
		if (error)
			break;
		
		// check for value within 0...255
		if ((number < 0) || (number > 255)) {
			error = ColorError;
			break;
		}

		// if no error then assign number to proper field
		switch (count) {
			case 1:
				result.rvalue = number;
				break;
			
			case 2:
				result.gvalue = number;
				break;
			
			case 3:
				result.bvalue = number;
				break;
			
			default:
				break;
		}
			
		// Remove comma separator if present
		
		if (count < components) {
			SkipSpace(next);
		
			if (*next == Comma) {
				next++;
				SkipSpace(next);
			}
		}
	}
	
	// if no error then use result to modify object
	// otherwise just return original object

	if (!error)
		return Set(result);
	else
		return *this;
}


string RGBdata::ToString(bool wide) const {
	// define stream
	stringstream stream;
	
	// format to the stream
	if (wide)
		stream << right
		       << setw(3) << short(rvalue) << ", "
		       << setw(3) << short(gvalue) << ", " 
		       << setw(3) << short(bvalue);
	else
		stream << short(rvalue) << ", "
		       << short(gvalue) << ", " 
		       << short(bvalue);
	
	// copy stream to string
	return stream.str();
}

