#define MSGS_OFF
#include <iostream.h>
#include <math.h>
#include <graphics.h>
#include <stdlib.h>
#include <conio.h>
#include <dos.h>

int maxx;
int maxy;
class Celestial
{
protected:
   double X, Y;
   int Size;
   virtual void Show(int) = 0;
   virtual void Recalc()
   {
   }
public:
   Celestial(double px, double py, int psize);
   double getX() const { return X; }
   double getY() const { return Y; }
   int getSize() const { return Size; }
   void Update();
};
Celestial :: Celestial(double px, double py, int psize) :
	     X(px), Y(py), Size(psize)
{
#ifdef MSGS
   cout << "Celestial created (" << X << " " << Y
	<< " " << Size << " )" << endl;
#endif
}
void Celestial :: Update()
{
   Show(0);
   Recalc();
   Show(1);
}
double dist(Celestial &a, Celestial &b)
{
   double dx = a.getX() - b.getX();
   double dy = a.getY() - b.getY();
   return sqrt(dx * dx + dy * dy);
}
class Star : public Celestial
{
   int Shown;
public:
   Star(int psize) : Celestial(maxx / 2, maxy / 2, psize),
                     Shown(0)
   {
   #ifdef MSGS
      cout << "star created" << endl;
   #endif
   }
   virtual void Show(int);
};
void Star :: Show(int bShow)
{
   if(!Shown)
   {
      setcolor( bShow ? (Shown = 1, YELLOW) : getbkcolor() );
      circle((int)X, (int)Y, Size);
   }
}
Star *sun;
class Planet : public Celestial
{
private:
   int R;
   const char *name;
   double Angle, DeltaAngle; //<----Изменения, естественно в конструкторе тип поменял

protected:
   virtual void Recalc()
   {
      Angle -= DeltaAngle;
      if(Angle < 0) Angle += 360;

      X = maxx/2 + R*cos(Angle*M_PI/180); //<----Изменения
      Y = maxy/2 + R*sin(Angle*M_PI/180); //
   }

public:
   Planet(double px, double py, int psize,
	  int pr, double pdeltaangle, const char *pname);
   virtual void Show(int);
};
Planet :: Planet(double px,double py, int psize,
		 int pr, double pdeltaangle, const char *pname) :
		 Celestial(px, py, psize),
		 R(pr), Angle(360), name(pname),
                 DeltaAngle(pdeltaangle)
{
   #ifdef MSGS
      cout << "planet " << name << " created ("
	   << R << " " << Angle << " )" << endl;
   #endif
}


void Planet :: Show(int bShow)
{
   setcolor( bShow ? LIGHTGREEN : getbkcolor() );
   circle((int)X, (int)Y, Size);
}
class Particle : public Celestial
{
private:
   double Vx, Vy;
public:
   Particle(double px, double py, double pvx, double pvy);
   ~Particle();
   virtual void Show(int);
   virtual void Recalc();
};
Particle :: Particle(double px, double py, double pvx, double pvy) :
	    Celestial(px, py, 1),
	    Vx(pvx), Vy(pvy)
{
   #ifdef MSGS
      cout << "particle created : Vx = " << Vx << " Vy = " << Vy << endl;
   #endif
}
Particle :: ~Particle()
{
   Show(0);
}
void Particle :: Show(int bShow)
{
   putpixel( (int)X, (int)Y, bShow ? LIGHTGRAY : getbkcolor() );
}
void Particle :: Recalc()
{
   Vx += ((getX() - sun->getX()) / dist(*sun, *this));
   Vy += ((getY() - sun->getY()) / dist(*sun, *this));
   X += Vx;
   Y += Vy;
}
const int parrSize = 1500;
const int stepParticles = 15;
const int maxPartSpeed = 3;
class Comet : public Celestial
{
private:
   double Ex, Ey;
   int Vx, Vy;
   Particle *trace[parrSize];
   int maxParticles;
private:
   int Cvt(int curr);
protected:
   virtual void Recalc();
public:
   Comet(double px, double py, int psize, int pvx, int pvy);
   virtual void Show(int);
 int OutOfSystem()
   {
      return (X < -5 || X > maxx + 5 || Y < -5 || Y > maxy + 5) ? 1 : 0;
   }
};
Planet *earth, *mars;
Comet *c_01;
int Comet :: Cvt(int curr)
{
   int sign;
   if(!curr) sign = 0;
   else sign = curr / abs(curr);
   return sign * random(maxPartSpeed - abs(curr));
}
Comet :: Comet(double px, double py, int psize, int pvx, int pvy) :
	 Celestial(px, py, psize),
	 Vx(pvx), Vy(pvy), maxParticles(100)
{
   Ex = (sun->getX() - sun->getSize()) / maxPartSpeed;
   Ey = (sun->getY() - sun->getSize()) / maxPartSpeed;
   for(int i = 0; i < maxParticles; i++)
   {
      double dx = (px - sun->getX());
      double dy = (py - sun->getY());
      #ifdef MSGS
	 cout << "i = " << i << " Dx = " << dx << " Dy = " << dy << endl;
      #endif
      trace[i] = new Particle(px - 1 + random(2), py - 1 + random(2),
			      Vx + Cvt((int)(dx / Ex)) - 1 + random(2),
			      Vy + Cvt((int)(dy / Ey)) - 1 + random(2));
   }
   #ifdef MSGS
      cout << "comet created (" << Vx << " " << Vy << " )" << endl;
      cout << "dist to sun = " << dist(*sun, *this) << endl;
   #endif
}
void Comet :: Recalc()
{
   X += Vx;
   Y += Vy;
   #ifdef MSGS
      cout << "comet : dist to sun = " << dist(*sun, *this) << endl;
   #endif
   int count = 0;
   for(int i = 0; i < maxParticles; i++)
   {
      trace[i]->Recalc();
      double d = dist(*trace[i], *this);
      #ifdef MSGS
	 cout << "i = " << i << " Dist = " << d << endl;
      #endif
      if(d > 25 * Size)
      {
	 delete trace[i];
	 count += 1;
	 trace[i] = new Particle((int)(getX()) - 1 + random(2), (int)(getY()) - 1 + random(2),
				 Vx + Cvt((int)((getX() - sun->getX()) / Ex)) - 1 + random(2),
				 Vy + Cvt((int)((getY() - sun->getY()) / Ey)) - 1 + random(2));
      }
   }
   #ifdef MSGS
      cout << count << " new particles created" << endl;
   #endif
   for(i = 0; i <= stepParticles - count; i++)
   {
      trace[maxParticles + i] = new Particle((int)(getX()) - 1 + random(2), (int)(getY()) - 1 + random(2),
				    Vx + Cvt((int)((getX() - sun->getX()) / Ex)) - 1 + random(2),
				    Vy + Cvt((int)((getY() - sun->getY()) / Ey)) - 1 + random(2));
   }
   if(stepParticles - count > 0)
      maxParticles += (stepParticles - count);
   #ifdef MSGS
      cout << maxParticles << " currently. Max = " << parrSize << endl;
   #endif
}
void Comet :: Show(int bShow)
{  setcolor( bShow ? WHITE : getbkcolor() );
   circle((int)X, (int)Y, Size);
   for(int i = 0; i < maxParticles; i++)
      trace[i]->Show(bShow);
}
class Observer
{
public:
   Observer();
   ~Observer();
   void Run();
};
Observer :: Observer()
{
   int gdriver = DETECT, gmode, errorcode;
   initgraph(&gdriver, &gmode, "../BGI");
   errorcode = graphresult();
   if(errorcode != grOk)
   {
      cerr << "Graphics error: " << grapherrormsg(errorcode) << endl;
      exit(-1);
   }
   maxx = getmaxx(); maxy = getmaxy();
   randomize();
}
Observer :: ~Observer()
{
   closegraph();
}
void Observer :: Run()
{
   while(1)
   {
      sun->Update();
      earth->Update();
      mars->Update();
     // c_01->Update();
      if(kbhit())
      {
	 if(getch() == 27) break;
      }
      /*
      if(c_01->OutOfSystem()) // Проверяем, если вышли за пределы - то пересоздаем комету...
      {
         delete c_01;
	 c_01 = new Comet(rand()%maxx, maxy, 2, 5, -5);
      }
      */
      delay(5);
   }
}
int main()
{
   Observer obj;
   sun = new Star(10);
   earth = new Planet(maxx / 2.+ 3 * 20, maxy / 2., 3,
		      60, 360./365., "earth");
   mars = new Planet(maxx / 2.+ 4 * 20, maxy / 2., 3,
		      80, 360./687., "mars");
   //c_01 = new Comet(rand()%maxx, maxy, 2, 5, -5);
   obj.Run();
   return 0;
}