#include "demo.h"



vert_t * make_fixpoint(float x, float y)
{
  vert_t * ret = get_new_vert();

  ret->polar = false;
  ret->x = ret->screen_x = x;
  ret->y = ret->screen_y = y;
  ret->angl = 0;
  
  ret->anchor = NULL;

  return ret;
}



vert_t * make_polar(float angl, float dist)
{
  vert_t * ret = get_new_vert();

  ret->polar = true;
  ret->angl = ret->temp_angl = angl;
  ret->dist = dist;

  ret->anchor = NULL;

  return ret;
}



vert_t * make_anchor(vert_t * original)
{
  vert_t * ret = get_new_vert();

  ret->anchor = original;

  return ret;
}



vert_t * clone_mirr(vert_t * original)
{
  ASSERT(original != NULL);
  ASSERT(original->polar);
  
  vert_t * ret = clone_vert(original);

  original->angl *= -1;

  return ret;
}



vert_t * clone_vert(vert_t * original)
{
  ASSERT(original != NULL);
  
  vert_t * ret = get_new_vert();

  memcpy(ret, original, sizeof(vert_t));
    
  return ret;
}



poly_t * clone_poly(poly_t * original)
{
  ASSERT(original != NULL);

  poly_t * ret = make_poly(original->origin);

  memcpy(ret, original, sizeof(poly_t));

  ret->first_edge = ret->last_edge = NULL;

  for (edge_t * e = original->first_edge; e; e = e->next)
  {
    add_edge(ret, e->start, e->end);
  }
  
  return ret;
}



poly_t * make_poly(vert_t * origin)
{
  poly_t * ret = get_new_poly();

  ASSERT(ret != NULL);
  ASSERT(origin != NULL);
  
  ret->origin = origin;
  ret->first_edge = ret->last_edge = NULL;
  ret->rotation = 0;
  ret->scale = 1;
  ret->visible = 1;
  ret->link_angl = false;
  ret->thicc = DEF_THICC;
  ret->flicker = false;
  ret->single_color = false;
  
  return ret;
}



edge_t * add_edge(poly_t * poly, vert_t * start, vert_t * end)
{
  edge_t * edge = get_new_edge();

  edge->start = start;
  edge->end = end;

  edge->next = NULL;
  
  if (poly->first_edge == NULL)
  {
    poly->last_edge = poly->first_edge = edge;
  }
  else
  {
    poly->last_edge->next = edge;
    poly->last_edge = edge;
  }

  edge->color = cl_white;

  return edge;
}



poly_t * make_ngon(vert_t * origin, float radius, int sides, int step)
{
  ASSERT(sides <= 100);
  
  poly_t * ret = make_poly(origin);
  vert_t * vert[100];
  int i;
  
  for (i = 0; i < sides; i++)
  {
    vert[i] = make_polar(((float)FULL_CIRCLE / (float)sides) * (float)i, radius);
  }

  for (i = 0; i < sides; i++)
  {
    add_edge(ret, vert[i], vert[(i + step) % sides]);
  }

  return ret;
}



edge_t * add_fedge(poly_t * poly, float from_x, float from_y, float to_x, float to_y)
{
  ASSERT(poly != NULL);

  return add_edge(poly, make_fixpoint(from_x, from_y), make_fixpoint(to_x, to_y));
  
  vert_t * start = NULL;
  vert_t * end = NULL;

  for (edge_t * e = poly->first_edge; e; e = e->next)
  {
    if (e->end->x == from_x && e->end->y == from_y)
    {
      start = e->end;
    }

    if (e->start->x == to_x && e->start->y == to_y)
    {
      end = e->start;
    }
  }

  if (!start)
    start = make_fixpoint(from_x, from_y);

  if (!end)
    end = make_fixpoint(to_x, to_y);

  return add_edge(poly, start, end);
}



edge_t * add_cedge(poly_t * poly, float to_x, float to_y)
{
  ASSERT(poly != NULL);

  if (poly->first_edge == NULL)
    return add_edge(poly, make_fixpoint(0, 0), make_fixpoint(to_x, to_y));

  ASSERT(poly->last_edge != NULL);

  return add_edge(poly, poly->last_edge->end, make_fixpoint(to_x, to_y));
}



void join_edges(poly_t * a, poly_t * b)
{
  ASSERT(a != NULL);
  ASSERT(b != NULL);

  if (a->last_edge)
  {
    a->last_edge->next = b->first_edge;
    a->last_edge = b->last_edge;
  }
  else
  {
    a->first_edge = b->first_edge;
    a->last_edge = b->last_edge;
  }

  b->first_edge = b->last_edge = NULL;
  
  return;
}



poly_t * make_text(vert_t * origin, char * text)
{
  ASSERT(text != NULL);

  poly_t * ret = make_poly(origin);

  ret->text = text;
  ret->color = cl_white;
  ret->font = 0;

  return ret;
}



vert_t * fix_to_polar(float origin_x, float origin_y, float fix_x, float fix_y)
{
  vert_t * ret = get_new_vert();

  float a = (fix_x - origin_x);
  float b = (fix_y - origin_y);
  float c = sqrt(a * a + b + b);
  
  ret->dist = c;
  ret->angl = asinf(a / c);

  return ret;
}



void dump_vert(vert_t * vert)
{
  ASSERT(vert != NULL);
  
  printf("vert_t * %p polar=%d angl=%f dist=%f x=%f y=%f\n",
         vert,
         vert->polar,
         vert->angl,
         vert->dist,
         vert->x,
         vert->y);

  return;
}



void dump_poly(poly_t * poly)
{
  ASSERT(poly != NULL);
  
  printf("poly_t * %p: scale=%f\n", poly, poly->scale);

  for (edge_t * e = poly->first_edge; e; e = e->next)
  {
    printf("  edge_t * %p:\n    ", e);
    dump_vert(e->start);
    printf("    ");
    dump_vert(e->end);
  }

  return;
}



vert_t * edge_end(edge_t * edge)
{
  ASSERT(edge != NULL);

  return edge->end;
}



poly_t * convert_polar(poly_t * orig, float origin_x, float origin_y)
{
  ASSERT(orig != NULL);

  poly_t * ret = make_poly(make_fixpoint(0, 0));

  for (edge_t * e = orig->first_edge; e != NULL; e = e->next)
  {
    vert_t * new_start = vert_to_polar(e->start, origin_x, origin_y);
    vert_t * new_end = vert_to_polar(e->end, origin_x, origin_y);

    add_edge(ret, new_start, new_end);
  }
  
  return ret;
}



vert_t * vert_to_polar(vert_t * v, float origin_x, float origin_y)
{
  float dist_x = (float)(v->x - origin_x);
  float dist_y = (float)(v->y - origin_y);
      
  vert_t * r = get_new_vert();
  
  r->polar = true;
  r->angl = atan2f(dist_y, dist_x) / RADIAN;
  r->dist = sqrtf(dist_x * dist_x + dist_y * dist_y);

  return r;
}



void normalize_origin(poly_t * poly)
{
  ASSERT(poly != NULL);

  vert_t * visited[1000];
  int vis_i = 0;
  vert_t * v[2];

  float off_x = poly->origin->x;
  float off_y = poly->origin->y;
  
  for (edge_t * e = poly->first_edge; e != NULL; e = e->next)
  {
    v[0] = e->start;
    v[1] = e->end;

    for (int v_i = 0; v_i < 2; v_i++)
    {
      for (int j = 0; j < vis_i; j++)
      {
        if (visited[j] == v[v_i])
          goto next_vert;
      }

      visited[vis_i++] = v[v_i];

      if (vis_i >= 1000)
      {
        printf("SHIT, ran out of vert space");
        return;
      }
      
      v[v_i]->x += off_x;
      v[v_i]->y += off_y;
  
    next_vert:
      ;
    }
  }
  
  return;
}
