// ***************************************************
// Program z paragrafu   15.1.1 (str 663)
// ***************************************************

// Sprawdzony na Linuksie, kompilator: GNU gcc version 3.3.3 (SuSE Linux)
// Sprawdzony na Windows XP,  kompilator: Microsoft Visual C++ 6.0

// Program ten zostal gruntownie przerobiony (Patrz: opis na dole)

#include <iostream>
using namespace std ;


#include <cstring>                    // strcpy
#include <cmath>                    // log, pow
#include <ctime>                    // time

// deklaracje funkcji pomocniczych
char* liczba_na_napis(char *gdzie, int wartosc);
void zwloka(int sekund) ;

// ***********************************************************
// Aby mozliwe bylo pisanie na ekranie w miejscach o okreslonych
// wspolrzednych stosuje pewien chwyt. Otoz zamiast pisac wprost
// na ekranie, - "piszemy" w tablicy znakowej o rozmiarach [25][80].
// Takie zwykle sa monitory alfanumeryczne: maja one 80 znakow w linii,
// a na ekranie jest takich linii 25
// Funkcja skladowa o nazwie wyczysc, kasuje poprzednia tresc
// "ekranu", i zapelnia wstepnie kropkami. (Pierwotnie zapelnialem
// spacjami, ale teraz kropki podobaja mi sie bardziej).
// Dodatkowo na koncu kazdej linii wpisywany jest znak nowej linii
// a na samy koncu jest znak null. Dzieki temu, te dwuwymiarowa
// tablice mozemy wypisac na ekranie jedna instrukcja - jako jeden
// string, ktory w okreslonych miejscach ma znaki przejscia do nowej
// linii.

// Gdy taka tablica znakow jest juz zapelniona sensowna trescia, wypisujemy
// ja na ekranie funkcja skladowa o nazwie wyswietl.

// Oczywiscie wszystko to ma sens tylko wtedy gdy czcionki piszace
// po ekranie sa proporcjonale - czyli gdy szerokosc wszystkich znakow
// jest taka sama. (znak 'W' jest tak samo szeroki jak znak '.').
// Tak wlasnie jest w wypadku ekranu alfanumerycznego.
// Jesli u Ciebie jest inaczej, zmien czcionke na proporcjonalna,
// (porporcjonalna jest na przyklad czcionka "Courier").


// ***********************************************************
class ekran_alfanumeryczny
{
	char tresc[25][80] ;
public:
	//--------------------
	void wyczysc()
	{
     system("cls");
		// wypelnienie calego "ekranu" samymi kropkami
		memset(tresc, '.' , sizeof(tresc) );
		
		// wstawienie znakow przejscia do nowej linii ekranowej
		// na koncu kazdej linii
		for(int i = 0 ; i < 25 ; i++)
		{
			tresc[i][79] = '\n';
		}
		// ostatecznie wstawienie znaku null konczacego obrazek
		tresc[24][79] = 0;  // <--- null
	}
	//--------------------
	void wyswietl()
	{
		cout << &tresc[0][0] << flush ;
	}
	//-------------------
	// funkcja skladowa wpisujaca w miejscu o wspolrzednych x,y
	// zadany tekst
	void napisz(int x, int y, const char* tekst)
	{
		for(unsigned int i = 0 ; i < strlen(tekst) ; i++)
			tresc[y][x+i] =  tekst[i];
	}
};
//////////////////////////////////////////////////////////////////////////////
ekran_alfanumeryczny ekran ;  // definicja globalnego obiektu ekran

//////////////////////////////////////////////////////////////////////////////
class przyrzad {
	char nazwa[20] ;
	char jednostki[10] ;
	int pokazuje ;
	int x, y, min, max ;     // gdzie jest na ekranie ten przyrzad
	static int ile_nieznanych ;                       //
	
public :
	
	// konstruktory
	przyrzad (int, int, const char *, const char *, int, int, int = 0) ; //
	
	przyrzad (void) ;
	
	// zwykle funkcje skladowe
	void zmien (int w ) ;
	void narysuj (void);
} ;
/////////////////////////////////////////////////////////
// definicje konstruktorow
//*******************************************************
przyrzad::przyrzad(int xx, int yy, const char * nnn,
				   const char * jedn,int _max, int _min,  int w)
{
	strcpy(nazwa, nnn);
	strcpy(jednostki, jedn);
	pokazuje = w ;
	x = xx ;
	y = yy ;
	min=_min;
	max=max;
	narysuj() ;                                    //
}
//*******************************************************
przyrzad::przyrzad(void)                          //
{
	char tmp[20] = "" ;
	min=0;
	max=100;
	
	++ile_nieznanych ;          // jeszcze jeden nieznany wskaznik
	
	strcpy(jednostki, " ");
	
	// wypelnienie tablicy tekstem - "Wskaznik nr n"
	strcpy(nazwa, "Wskaznik nr ");
	liczba_na_napis(tmp, ile_nieznanych);
	strcat(nazwa, tmp);
	
	// wymyslenie dla przyrzadu jego pozycji na ekranie
	x = 45 ;
	y = 1+ (ile_nieznanych-1) * 4 ;                 //
	
	pokazuje = 0 ;          // co ma on pokazywac
	
	// narysowanie go na ekranie
	narysuj();
}
//******** dalsze funkcje skladowe **********************************
//*****************************************************************
void przyrzad::zmien(int w)
{
	pokazuje = w ;
	narysuj();
}
//******************************************************
void  przyrzad:: narysuj()
{
	// Tej funkcji ladnie nie definiujemy.
	// Nie uzywamy tu bowiem zadnej bibiloteki graficznej (grafika
	// nie nalezy do standardu!)
	// Markujemy wobec tego wyswietlaczem cyfrowym
	
	// Najpierw wypelniona ramka
	ekran.napisz(x, y, " ___________________________");
	ekran.napisz(x, y+1,  "I                           I" );
	ekran.napisz(x, y+2,  "I                           I" );
	if ((pokazuje > min) && (pokazuje < max)) ekran.napisz(x, y+3,  "I___________________________I" );
	else ekran.napisz(x, y+3,  "I________________!!!________I" );
	
	// Rysowanie wypelnionej spacjami ramki bylo najpierw.
	// Ta kolejnosc jest wazna, bo spacje ze stringow powyzej
	// zamazalyby teksty, ktore napiszamy ponizej.
	
	
	ekran.napisz(x+5, y+1,  nazwa );
	
	
	char tablica_na_liczbe[20] = "" ;
	ekran.napisz(x+7, y+2,  liczba_na_napis(tablica_na_liczbe, pokazuje) ) ;
	ekran.napisz(x+14, y+2, jednostki );
	ekran.wyswietl();
}
//=====================================================
int przyrzad::ile_nieznanych ;                        //
//=====================================================
int main()
{
	ekran.wyczysc() ;   //
	
	// definicje obiektow  ---------------------
	przyrzad Pred(2, 1, "Predkosc", "wezlow",120, 115, 110);//
	przyrzad Vari(2, 6, "Wznoszenie", "stopy/sec",120,130);//
	przyrzad A ;                                   //
	przyrzad B ;
	volatile przyrzad C ;                          //
	
	const przyrzad Udzw (2, 11, "Udzwig maksymalny",
		"ton",1,16000, 15000 );                   //
	
	
	// symulacja normalnego ciaglego wyswietlania ----
	for(int i = 0 ; i < 30 ; i++){                  //
		Vari.zmien(i);
		Pred.zmien(110+i);
		A.zmien(-i);
		B.zmien(i % 4) ;
		// C.zmien(i % 3);          // obiekt volatile
		// Udzw.zmien(270);         // obiekt const
		
		zwloka(1) ;
		
	}
}
// *********************************************************************
// Zostala tez zdefiniowanea funkcja dokonujaca zamiany liczby na
// reprezentacje alfanumeryczna. Odpowiada to dawnej funkcji o nazwie
// (itoa Integer TO Ascii)
// Oczywiscie zamiast definiowac te funkcje moglem sie posluzyc
// klasami do tzw. formatowania wewnetrzego, ale w tym miejscu w ksiazce
// nie zostaly one jeszcze omowione
// *********************************************************************
char*  liczba_na_napis(char *gdzie, int wartosc)
{
	int pozycja = 0 ;
	if(wartosc == 0)    gdzie[pozycja++] = '0' ;  // cyfra zero
	else
    {
		if(wartosc < 0)
		{
			gdzie[pozycja++] = '-' ; // wpisujemy znak minus
			wartosc = -wartosc ;    // i odtad pracujemy jak z liczba dodatnia     
		}
		
		int reszta = wartosc ;
		int pulap_dolny = (int) pow(10.0 , (int) log10((double) wartosc) ) ;
		// pulap dolny to najblizsza wartosc potegi 10 nie wieksza niz 
		// zadana wartosc. Np dla wartosci 852 pulap ten to jest 100  
		
		for( ; pulap_dolny > 0  ; pozycja++, pulap_dolny /= 10)
		{
			int cyfra = reszta / pulap_dolny ;
			reszta = reszta % pulap_dolny ;
			gdzie[pozycja] =  '0' + cyfra ;
		}
		
    } // end else
	if (wartosc>125) {gdzie[pozycja]=33;pozycja++;}
	gdzie[pozycja] =  0 ; // dopisz konczacy null;
	return gdzie ;
}
// ********************************************************
// Dodatkowo zdefiniowalem funkce zwloka, ktora powoduje w programie
// zwloke czasowa o dlugosci zadanej liczby sekund
// ********************************************************
void zwloka(int sekund)
{
	static time_t poprzedni_czas = time(NULL) ;
	while(time(NULL) - poprzedni_czas < sekund)  ;   // cialo puste
	
	poprzedni_czas = time(NULL) ;
}
/************************************************************
		  
************************************************************/

