#include <cstdlib>
 #include <iostream>
 #include <cmath>
 #include <vector>
 #include <fstream>


 #  include <GL/glut.h>

 #define PI 3.14159265
 static int isAnimate = 0;

 static float t = 0.0;
 static float R = 20.0;
 static float lw = 3,ts=3;
 static float Xvalue = 0.0, Yvalue = 0;
 static float Angle = 0.0;
 using namespace std;

 
 static int animateMode = 0; 
 static int animationPeriod = 1000; 


 // Camera class.
 class Camera
 {
 public:
    Camera();
    void incrementViewDirection();
    void decrementViewDirection();
    void incrementZoomDistance() { zoomDistance += 1.0; }
    void decrementZoomDistance() { zoomDistance -= 1.0; }

    float getViewDirection() const { return viewDirection; }
    float getZoomDistance() const { return zoomDistance; }

 private:
    float viewDirection;
    float zoomDistance;
 };

 // Global camera.
 Camera camera;

 // Camera constructor.
 Camera::Camera()
 {
    viewDirection = 0.0;
    zoomDistance = 30.0;
 }

 
 void Camera::incrementViewDirection()
 {
    viewDirection += 5.0;
    if (viewDirection > 360.0) viewDirection -= 360.0;
 }

 void Camera::decrementViewDirection()
 {
    viewDirection -= 5.0;
    if (viewDirection < 0.0) viewDirection += 360.0;
 }
 void drawHelix(void)
 {
         float k = 0;
         glClear(GL_COLOR_BUFFER_BIT);
         glColor3f(0.0,1.0, 1.0);
         glLineWidth(lw);
 //glTranslatef(Xvalue, Yvalue, -5.0);
 gluLookAt(camera.getZoomDistance() *
 sin(camera.getViewDirection()*PI/180.0), 0.0,
                  camera.getZoomDistance() *
 cos(camera.getViewDirection()*PI/180.0), 0.0,
                          0.0, 0.0, 0.0, 1.0, 0.0);
         glRotatef(Angle, 0.0, 0.0, 1.0);
         glBegin(GL_LINE_STRIP);
         for (k = -10 * PI; k <= 10 * PI; k += PI / 20.0)
                 glVertex3f(R * cos(k), k, R * sin(k) - 60.0);
         glEnd();
 }
 void DrawBall()
 {
         glClear(GL_COLOR_BUFFER_BIT);
         glLoadIdentity();
         drawHelix();
         glTranslatef(0.0, -35.0,-5.0);
         glTranslatef(R * cos(t), t, R * sin(t) - 60.0);
         glColor3f(1.0, 0.0, 0.0);
         glutWireSphere(ts, 30, 10);
 }
 void drawScene(void)
 {
         DrawBall();
         glFlush();
         glutSwapBuffers();
 }
 void animate(int value)
 {
         if (isAnimate)
         {
                 if (t < 21.9 * PI && t >= 0)
                 {
                         t += 0.1;
                         glutPostRedisplay();
                         glutTimerFunc(animationPeriod, animate, 1);
                 }
         }
 }
 void animate1(int value)
 {
         if (isAnimate)
         {
                 if (t < 21.9 * PI && t >= 0)
                 {
                         t -= 0.1;
                         glutPostRedisplay();
                         glutTimerFunc(animationPeriod, animate1, 1);
                 }
         }
 }
 void setup(void)
 {
         glClearColor(0.0, 0.0, 0.0, 0.0);
 }
 void resize(int w, int h)
 {
         glViewport(0, 0, w, h);
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         glFrustum(-10.0, 10.0, -10.0, 10.0, 5.0, 100.0);

         glMatrixMode(GL_MODELVIEW);
 }
 void keyInput(unsigned char key, int x, int y)
 {
         switch (key)
         {
         case 27:
                 exit(0);
                 break;
         case ' ':
                 Angle += 10.0;
                 glutPostRedisplay();
                 break;
         case 'w':
                 if (lw<=7)
                 lw +=1;
                 glutPostRedisplay();
                 break;
         case 's':
                 if (lw >1)
                         lw -= 1;
                 glutPostRedisplay();
                 break;
         case 'e':
                 if (ts <=7)
                         ts +=1;
                 glutPostRedisplay();
                 break;
         case 'd':
                 if (ts > 1)
                         ts -= 1;
                 glutPostRedisplay();
                 break;
         case '+':
                 if (R <=30)
                         R += 1;
                 glutPostRedisplay();
                 break;
         case '-':
                 if (R >10)
                         R -=1;
                 glutPostRedisplay();
                 break;
         case 'b':
                 if (isAnimate) isAnimate = 0;
                 else
                 {
                         isAnimate = 1;
                         animate(1);
                 }
                 break;
         case 'c':
                 if (isAnimate) isAnimate = 0;
                 else
                 {
                         isAnimate = 1;
                         animate1(1);
                 }
                 break;
         case 'r':
                 isAnimate = 0;
                 t = 0.0;
                 glutPostRedisplay();
                 break;
 case 'g': camera.incrementViewDirection();
          glutPostRedisplay();break;
 case 'G':camera.decrementViewDirection();
          glutPostRedisplay();break;
                  break;
 case 'z': // Zoom in.
              camera.decrementZoomDistance();
          glutPostRedisplay();
                  break;
           case 'Z': // Zoom out.
              camera.incrementZoomDistance();
          glutPostRedisplay();
                  break;
         default:
                 break;
         }
 }
 void specialKeyInput(int key, int x, int y)
 {
         if (key == GLUT_KEY_UP) Yvalue += 1.0;
         if (key == GLUT_KEY_DOWN) Yvalue -= 1.0;
         if (key == GLUT_KEY_LEFT) Xvalue -= 1.0;
         if (key == GLUT_KEY_RIGHT) Xvalue += 1.0;
         glutPostRedisplay();
 }
 
 
 int main(int argc, char **argv)
 {
       
         glutInit(&argc, argv);
         glutInitWindowSize(500, 500);
         glutInitWindowPosition(800, 100);
         glutCreateWindow("helix and sphere");
         glutDisplayFunc(drawScene);
         glutReshapeFunc(resize);
         glutKeyboardFunc(keyInput);
         glutSpecialFunc(specialKeyInput);
         setup();
         glutMainLoop();
 }