//-----------------------------------------
#include <stdio.h>
#include <math.h>


#define pi       3.1416
#define ID_TM_MAIN    100
#define INTERVAL     50
#define FLOORTHICK    150
#define SCALE      (WndWidth/10.0)


void DrawFloor (int Thickness, int R, int G, int B);


class CBall
{
private:
 double Radius, Mass, RInertia, ContactSpeed;
 struct { double position; double speed; } Linear;
 struct { double angle; double speed; } Angular;
 struct { double Static; double kinetic; } Friction;


public:
 CBall (double Radius, double Mass, double Lspeed, double Aspeed, double Fkinetic, double Fstatic = 0.50)
 {
  CBall::Radius = Radius;
  CBall::Mass = Mass;

  CBall::Linear.speed = Lspeed;
  CBall::Linear.position = 0;

  CBall::Angular.speed = Aspeed;
  CBall::Angular.angle = 0;
  
  Friction.kinetic = Fkinetic;
  Friction.Static = Fstatic;

  RInertia = (2.0/5.0)* pow(Radius, 2.0)* Mass;
 };

 ~CBall (void)
 {};


 void Move (int Interval)
 {
  const double g = 9.80;
  double dt = (double)Interval / 1000;
  double Force;

  ContactSpeed = Linear.speed + Radius* Angular.speed;

  if(ContactSpeed > 0)
   Force = -Mass* g* Friction.kinetic;
  else if (ContactSpeed < 0)
   Force = Mass* g* Friction.kinetic;
  else if (ContactSpeed == 0)
   Force = 0;

  Linear.speed += Force / Mass* dt;
  Angular.speed += Radius* Force / RInertia* dt;

  Linear.position += Linear.speed* dt;
  Angular.angle += Angular.speed* dt;

  InvalidateRect(hWnd, NULL, TRUE);
 };


 void Draw (HDC hDC, int R, int G, int B, int LineWidth=2)
 {

  char Print [32];
  sprintf(Print, "contact speed : %.2lf m/s", ContactSpeed);
  TextOutA(hDC, 10, 60, (LPSTR)Print, strlen(Print));
  sprintf(Print, "linear speed : %.2lf m/s", Linear.speed);
  TextOutA(hDC, 10, 75, (LPSTR)Print, strlen(Print));
  sprintf(Print, "angular speed : %.2lf rad/s", Angular.speed);
  TextOutA(hDC, 10, 90, (LPSTR)Print, strlen(Print));

  // Draw ball
  HBRUSH MyBrush, OldBrush;
  MyBrush = CreateSolidBrush(RGB(R, G, B));
  OldBrush = (HBRUSH)SelectObject(hDC, MyBrush);

  Ellipse(hDC, (Linear.position-Radius)*SCALE, -2*Radius*SCALE, (Linear.position+Radius)*SCALE, 0*SCALE);

  SelectObject(hDC, OldBrush);
  DeleteObject(MyBrush);

  // Draw line
  HPEN MyPen, OldPen;
  MyPen = CreatePen(PS_DASH, LineWidth, RGB(192-R, 192-G, 192-B));
  OldPen = (HPEN)SelectObject(hDC, MyPen);

  MoveToEx(hDC, Linear.position*SCALE, -Radius*SCALE, NULL);
  LineTo(hDC, (Linear.position + Radius*cos(Angular.angle))*SCALE, -(Radius*(1+sin(Angular.angle)))*SCALE);

  SelectObject(hDC, OldPen);
  DeleteObject(MyPen);
 }

};


HDC hDC;


CBall Ball (/*Radius*/0.3, /*Mass*/1.0,
     /*LinearSpeed*/0.0, /*AngularSpeed*/-5*pi, /*KineticCoefficient*/0.015);



LRESULT CALLBACK WndProc (HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{

 PAINTSTRUCT ps;
 char Print [64];


 switch(iMessage) {
 case WM_CREATE : 
  return 0;

 case WM_PAINT :
  hDC = BeginPaint(hWnd, &ps);
  SetViewportOrgEx(hDC, 0, WndHeight - FLOORTHICK, NULL);

  DrawFloor(FLOORTHICK, 192, 192, 192);
  Ball.Draw(hDC, 0, 0, 192);

  sprintf(Print, "%s", "과베저장소 | www.kwabe.com");
  SetTextAlign(hDC, TA_RIGHT);
  TextOutA(hDC, WndWidth - 20, 90, (LPSTR)Print, strlen(Print));

  EndPaint(hWnd, &ps);
  return 0;
 
 case WM_TIMER :
  switch(wParam) {
  case ID_TM_MAIN :
   Ball.Move(INTERVAL);
   break;
  }
  return 0;
  
 case WM_RBUTTONDOWN :
  SetTimer(hWnd, ID_TM_MAIN, INTERVAL, NULL);
  return 0;

 case WM_DESTROY :
  KillTimer(hWnd, ID_TM_MAIN);
  PostQuitMessage(0);
  return 0;
 }

 return DefWindowProc(hWnd, iMessage, wParam, lParam);

}


void DrawFloor (int Thickness, int R, int G, int B)
{

 HBRUSH MyBrush, OldBrush;
 MyBrush = CreateSolidBrush(RGB(R, G, B));
 OldBrush = (HBRUSH)SelectObject(hDC, MyBrush);

 Rectangle(hDC, 0, 0, WndWidth, Thickness);

 SelectObject(hDC ,OldBrush);
 DeleteObject(MyBrush);

}