import txt_read

import contour
import block
import contact
import path
import move

import math as m

#################### READ.
def read_txt(name, mp_trace, angle):
  C = [] ; R = [] ; S = []
  groupMax = 0

  with open(name + '.txt', 'r', encoding = "ISO-8859-1") as f:
    for line in f:
      if line[0] == 'Z':
        Z = float(line[1:])

      elif line[0] == 'K':
        C = [None]*int(line[1:])

      elif line[0] == 'N':
        R = [None]*int(line[1:])

      elif line[0] == 'C':
        line = line.replace('\n', '')
        c = line[1:].split(',')

        g = int(c[0])
        p = float(c[1])
        q = float(c[2])

        if C[g] == None:
          C[g] = list()
        
        C[g].append((p, q))

      elif line[0] == 'R':
        r = line[1:].split(",")

        p_x = float(r[1])
        p_y = float(r[2])

        q_x = float(r[3])
        q_y = float(r[4])

        p = (p_x, p_y)
        q = (q_x, q_y)

        if groupMax < int(r[6]):
          groupMax = int(r[6])

        R[int(r[0])] = create_line(int(r[0]), p, q, int(r[5]), int(r[6]), mp_trace, angle)
      
      elif line[0] == 'L':
        line = line.replace('\n', '')
        l = line[1:].split(",")

        p0 = R[int(l[0].replace('L', ''))]['p'][0]
        q0 = R[int(l[0].replace('L', ''))]['p'][1]
        p1 = R[int(l[1].replace('L', ''))]['p'][0]
        q1 = R[int(l[1].replace('L', ''))]['p'][1]

        rasterLink0 = create_raster_link(l[2], p0, q0, p1, q1, mp_trace)
        rasterLink1 = create_raster_link(l[3], p0, q0, p1, q1, mp_trace)

        add_side(R[int(l[0].replace('L', ''))], R[int(l[1].replace('L', ''))], rasterLink0, rasterLink1)
        S.append((int(l[0].replace('L', '')), int(l[1].replace('L', '')), rasterLink0, rasterLink1))

  return Z, C, R, S, groupMax

#################### RASTER LINES + SIDES.
def check_points_line(p, q, mp, rbit, angle):
  if rbit == 0:
    r_move = move.make(p, q, mp)
  else:
    r_move = move.make(q, p, mp)

  if is_equal(p[1], q[1], 0.05):
    p_x = p[0]
    p_y = p[1]

    q_x = q[0]
    q_y = q[1]
  
  else:
    p_x = rotate_x(p[0], p[1], angle)
    p_y = rotate_y(p[0], p[1], angle)

    q_x = rotate_x(q[0], q[1], angle)
    q_y = rotate_y(q[0], q[1], angle)

  if p_y != q_y: 
    if(p_y > q_y):
      q_y = p_y
    else:
      p_y = q_y

  if p_x > q_x: 
    x_aux = q_x
    q_x = p_x
    p_x = x_aux

  p = (p_x, p_y)
  q = (q_x, q_y)

  return p, q, r_move

def create_line(sid, p, q, rbit, group, mp, angle):
  p, q, r_move = check_points_line(p, q, mp, rbit, angle)
  return {
      'sid': sid, 
      'p': [p, q],
      'move': r_move,
      'rbit': rbit,
      'group': group,
      'links': [[].copy(),[].copy()]
  }

def add_side(R1, R2, rasterLink0, rasterLink1):
  y1 = R1['p'][0][1]
  y2 = R2['p'][0][1]

  if y2 > y1:
    R1['links'][1].append([R2['sid'], rasterLink0, rasterLink1]) 
    R2['links'][0].append([R1['sid'], rasterLink0, rasterLink1]) 

  elif y1 > y2:
    R1['links'][0].append([R2['sid'], rasterLink0, rasterLink1]) 
    R2['links'][1].append([R1['sid'], rasterLink0, rasterLink1]) 

def create_raster_link(link, p0, q0, p1, q1, mp):
  if 'None' in link:
    raster_link = None
      
  else:
    aux = link.split(';')
    raster_link_points = list()
    raster_link = list()

    for index in range(len(aux)):
      p = aux[index].split('&')
      raster_link_points.append((float(p[0]), float(p[1])))

    for index in range(len(raster_link_points) - 1):
      p = raster_link_points[index]
      q = raster_link_points[index + 1]

      if is_same_point(p, p0, 0.05):
        p = p0
      elif is_same_point(p, q0, 0.05):
        p = q0
      elif is_same_point(p, p1, 0.05):
        p = p1
      elif is_same_point(p, q1, 0.05):
        p = q1

      if is_same_point(q, p0, 0.05):
        q = p0
      elif is_same_point(q, q0, 0.05):
        q = q0
      elif is_same_point(q, p1, 0.05):
        q = p1
      elif is_same_point(q, q1, 0.05):
        q = q1

      mv = move.make(p, q, mp)
      raster_link.append(mv)
    
    raster_link = path.from_moves(raster_link)
    
  return raster_link

#################### SPLIT + LIMIT.
def split_block(R, groupMax): 
  totalOriginal = groupMax + 1

  for i in range(0, totalOriginal):
    swap_later = False
    group = i
  
    for r in R:
      if swap_later == True:
        swap_later = False
        group = groupMax + 1

      if r['group'] == i:
        input_lines = 0
        output_lines = 0

        if len(r['links'][0]) > 1 or len(r['links'][1]) > 1:
          input_lines = len(r['links'][0])
          output_lines = len(r['links'][1])

          if input_lines > 1:
            group = groupMax + 1

          if output_lines > 1:
            swap_later = True

        r['group'] = group
        
        if r['group'] > groupMax:
          groupMax = r['group']

  return groupMax

def limit_block(R, groupMax, maxLimit, S):
  for i in range(0, groupMax + 1):
    group = i
    lines = 0

    for r in R:
      if r['group'] == i:
        if lines < maxLimit:
          lines = lines + 1
        else:
          lines = 1
          groupMax += 1
          group = groupMax

        r['group'] = group

  return groupMax

def delete_rasterLink(R):
  for index1 in range(len(R)):
    for edge in range(2):
      for indexLink in range(len(R[index1]['links'][edge])):
        index2 = R[index1]['links'][edge][indexLink][0]
        
        if R[index1]['group'] != R[index2]['group']:
          R[index1]['links'][edge][indexLink][1] = None
          R[index1]['links'][edge][indexLink][2] = None

          for indexLink2 in range(len(R[index2]['links'][1-edge])):
            if R[index2]['links'][1-edge][indexLink2][0] == index1:
              R[index2]['links'][1-edge][indexLink2][1] = None
              R[index2]['links'][1-edge][indexLink2][2] = None

#################### BLOCKS + CONTACTS.
def check_raster_link(BS, g0, g1, s):
  rl0 = s[2] ; rl1 = s[3]

  p0 = path.pini(block.choice(BS[g0], 0))
  q0 = path.pfin(block.choice(BS[g0], 0))

  p1 = path.pini(block.choice(BS[g1], 0))
  q1 = path.pfin(block.choice(BS[g1], 0))
  
  if rl0 != None:
    pr0 = path.pini(rl0)
    qr0 = path.pfin(rl0)

    if pr0 != p0 and pr0 != q0 and pr0 != p1 and pr0 != q1:
      rl0 = None
    
    elif qr0 != p0 and qr0 != q0 and qr0 != p1 and qr0 != q1:
      rl0 = None

  if rl1 != None:
    pr1 = path.pini(rl1)
    qr1 = path.pfin(rl1)

    if pr1 != p0 and pr1 != q0 and pr1 != p1 and pr1 != q1:
      rl1 = None
    
    elif qr1 != p0 and qr1 != q0 and qr1 != p1 and qr1 != q1:
      rl1 = None

  return rl0, rl1

def create_contact(S, R, BS, mp_trace, mp_jump, angle, scan_line):
  CS = []
  angle = -angle

  for s in S:
    r0 = R[s[0]]
    r1 = R[s[1]]
    
    if r0['group'] != r1['group']:
      p0 = r0['p'][0][0]
      q0 = r0['p'][1][0]
      y0 = r0['p'][0][1]
      wd0 = move.width(r0['move'])
      mv0 = r0['move']
      bc0 = BS[r0['group']]
      
      p1 = r1['p'][0][0]
      q1 = r1['p'][1][0]
      y1 = r1['p'][0][1]
      wd1 = move.width(r1['move'])
      mv1 = r1['move']
      bc1 = BS[r1['group']]

      xlo = max(min(p0, q0), min(p1, q1))
      xhi = min(max(p0, q0), max(p1, q1))
      ylo = (y0 + y1 + (wd0 - wd1)/2)/2
      yhi = (y0 + y1 + (wd0 - wd1)/2)/2

      if scan_line:
        rl0 = None
        rl1 = None

      else:
        rl0, rl1 = check_raster_link(BS, r0['group'], r1['group'], s)

      end0 = move.endpoints(mv0)
      end1 = move.endpoints(mv1)

      if (end0[0][1] != end0[1][1]) or (end1[0][1] != end1[1][1]):
        xlo_rotate = rotate_x(xlo, ylo, angle)
        ylo_rotate = rotate_y(xlo, ylo, angle)
        xlo = xlo_rotate
        ylo = ylo_rotate

        xhi_rotate = rotate_x(xhi, yhi, angle)
        yhi_rotate = rotate_y(xhi, yhi, angle)
        xhi = xhi_rotate
        yhi = yhi_rotate

      ct = contact.make((xlo, ylo), (xhi, yhi), mv0, mv1, bc0, bc1, rl0, rl1)
      CS.append(ct)

      block.add_ct(bc0, ct)
      block.add_ct(bc1, ct)

  return CS
  # ----------------------------------------------------------------------

def create_blocks(R, S, CTRS, group_max, mp_trace, mp_jump, angle, scan_line):
  BS = []
  CS = []

  for g in range(group_max + 1):
    ph = None
    qEnd = None

    for r in R:
      if r['group'] == g:
        if ph == None:
          ph = path.from_moves([r['move']])
        
        elif ph != None:
          raster_link = None

          for link in r['links'][0]:
            if r['group'] == R[link[0]]['group']:
              if link[1 + r['rbit']] != None:
                raster_link = link[1 + r['rbit']]
                p = raster_link.pt[0]
                q = raster_link.pt[1]

                if is_same_point(p, qEnd, 0.005) and is_same_point(q, move.pini(r['move']), 0.005):
                  ph = path.concat((ph, raster_link), True, True, mp_jump)
                
                elif is_same_point(q, qEnd, 0.005) and is_same_point(p, move.pini(r['move']), 0.005):
                  ph = path.concat((ph, path.rev(raster_link)), True, True, mp_jump)

          ph = path.concat((ph, path.from_moves([r['move']])), True, True, mp_jump)

        qEnd = move.pfin(r['move'])

    if ph != None:
      bc = block.from_paths([(ph, 0), path.rev(ph)])
      BS.append(bc)
  
  if len(CTRS) > 0:
    contour.find_contour(CTRS, BS)

  if len(S) > 0:
    CS = create_contact(S, R, BS, mp_trace, mp_jump, angle, scan_line)

  return BS, CS

####################
def is_same_point(A, B, tolerance):
  if (abs(A[0] - B[0]) < tolerance) and (abs(A[1] - B[1]) < tolerance):
    return True 
  return False

def is_equal(A, B, tolerance):
  if (abs(A - B) < tolerance):
    return True 
  return False


def rotate_x(x, y, angle):
  return ((x*m.cos(-angle) - y*m.sin(-angle))*100)/100.0

def rotate_y(x, y, angle):
  return ((x*m.sin(-angle) + y*m.cos(-angle))*100)/100.0
