
// SPDX-License-Identifier: CC-BY-NC-SA-4.0
//
// Copyright (C) 2026 Bit by Bit Signal Processing LLC (https://bxbsp.com)
//
// This work is placed under the "Creative Commons Attribution
// NonCommercial ShareAlike 4.0 International" license, known
// by the shortened acronym "CC-BY-NC-SA-4.0".
//
// This work is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// A CC-BY-NC-SA-4.0 license allows you to use this work for
// noncommercial purposes so long as attribution is made to the
// original author.  Modified versions of this work may be distributed,
// but only under the same license.  For further details, see the
// Creative Commons License "CC-BY-NC-SA-4.0".
//
// You should have received a copy of the CC-BY-NC-SA-4.0 license
// along with this work. If not, see
// <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
//


#include "displays.hh"
#include "global_beep.hh"
#include "draw_text.hh"
#include "event_types.hh"
#include "send_events.hh"
#include "touchscreen_calibration.hh"
#include "local_display.hh"

#define GRAPH_PANE   0
#define MENU_PANE    1
#define SCRATCH_PANE 2
#define NUM_PANES    3

bool touchscreen_calibration::handle_event(my_event& me)
{
  if(me.source_mouse)
    {
      d->touchscreen_calibration_in_progress = false;	  
      delete this;
      return true;
    }
  

  if(me.type == EVENT_TOUCH && me.num_touches==1)
    {
      int center_x = (cal_step==0 || cal_step==3) ? cal_offset_x           : width  - cal_offset_x;
      int center_y = (cal_step==1 || cal_step==3) ? height - cal_offset_y  : cal_offset_y;

      int this_me_x = me.c[0].x;
      int this_me_y = me.c[0].y;

      if( abs(last_me_x-this_me_x)<100  &&  abs(last_me_y-this_me_y)<100 )
	{
	  d->touchscreen_calibration_in_progress = false;	  
	  delete this;
	  return true;
	}

      printf("last_me_x=%d, this_me_x=%d, last_me_y=%d, this_me_y=%d\n",
	     last_me_x, this_me_x, last_me_y, this_me_y);

      
      int this_x = this_me_x * touchscreen_x_gain + touchscreen_x_offset;
      int this_y = this_me_y * touchscreen_y_gain + touchscreen_y_offset;

      if(cal_step>=4)
	{
	  return true;
	}
      if(cal_step==1)
	{
	  touchscreen_x_gain    = (width -  2*cal_offset_x) / (double)(this_me_x - last_me_x);
	  touchscreen_y_gain    = (height - 2*cal_offset_y) / (double)(this_me_y - last_me_y);
	  touchscreen_x_offset  = center_x - this_me_x * touchscreen_x_gain;
	  touchscreen_y_offset  = center_y - this_me_y * touchscreen_y_gain;

	  printf("Touchscreen gain measured as (%f,%f) with offset (%f,%f), subject to verification.\n",
		 touchscreen_x_gain, touchscreen_y_gain, touchscreen_x_offset, touchscreen_y_offset);
	}
      
      if(cal_step<2)
	{
	  cal_step++;
	  global_touch_recognized_beep();
	  last_x = me.c[0].x;
	  last_y = me.c[0].y;
	}
      else
	{
	  last_x = this_x * touchscreen_x_gain + touchscreen_x_offset;
	  last_y = this_y * touchscreen_y_gain + touchscreen_y_offset;
	  match_center_x = center_x;
	  match_center_y = center_y;
	  
	  if(abs(last_x-center_x)<cal_length_x && abs(last_y-center_y)<cal_length_y)
	    {
	      cal_step++;
	      match_color = GREEN;
	      global_entry_accepted_beep();
	      last_count = pointer_display_interval;
	    }
	  else
	    {
	      cal_step = 0;
	      match_color = RED;
	      global_entry_rejected_beep();
	      last_count = 2*pointer_display_interval;
	    }
	}

      last_me_x = this_me_x;
      last_me_y = this_me_y;

      return true;  // Event handled
    }
  else if(me.type == EVENT_RELEASE)
    {
      return true;  // Event handled
    }
  
  cal_step = 0;
  
  return false;  // Event not handled
}


void touchscreen_calibration::layout()
{
  offset.x = 0;
  offset.y = 0;
  width    = d->width;
  height   = d->height;
  window_subject_to_layout = false;

  clear(BLUE5);
  
  float designed_height = 1080.0;
  float designed_width  = 1920.0;
  float ratio_x = width / designed_width;
  float ratio_y = height / designed_height;
  ratio = (ratio_x<ratio_y) ? ratio_x : ratio_y;
  
  set_text_size(80 * ratio);

  draw_text("Touchscreen Calibration",
	    WHITE,
	    width/2,
	    100 * ratio,
	    DRAW_TEXT_X_CENTER|DRAW_TEXT_Y_TOP|DRAW_TEXT_ROTATE_0);
  

  set_text_size(50 * ratio);

  draw_text("Touch the blinking mark in 4 steps to calibrate",
	    WHITE,
	    width/2,
	    height/2,
	    DRAW_TEXT_X_CENTER|DRAW_TEXT_Y_CENTER|DRAW_TEXT_ROTATE_0);

    draw_text("Touch twice in the same place to abort",
	    WHITE,
	    width/2,
	    height/2+100,
	    DRAW_TEXT_X_CENTER|DRAW_TEXT_Y_CENTER|DRAW_TEXT_ROTATE_0);

    
  release_events();
  claim_events();
  layout_dirty = false;
  dirty = true;
}


void touchscreen_calibration::draw_dirty()
{
  dirty = false;
}


void touchscreen_calibration::draw_dynamic()
{
  if(blink_count>=blink_interval)
    {
      blink_on = !blink_on;
      blink_count = 0;
    }
  else
    {
      blink_count++;
    }


  if(blink_on)
    {
      point p0, p1;

      int center_x = (cal_step==0 || cal_step==3) ? cal_offset_x           : width  - cal_offset_x;
      int center_y = (cal_step==1 || cal_step==3) ? height - cal_offset_y  : cal_offset_y;

      p0.x = center_x - cal_length_x;
      p1.x = center_x + cal_length_x;
      p0.y = center_y;
      p1.y = center_y;
      
      draw_line_horizontal(p0, p1, WHITE);
	  
      p0.x = center_x;
      p1.x = center_x;
      p0.y = center_y - cal_length_y;
      p1.y = center_y + cal_length_y;

      draw_line_vertical(p0, p1, WHITE);
    }

  if(last_count)
    {
      last_count--;

      if(!last_count && cal_step==4)
	{
	  d->touchscreen_calibrated              = true;
	  d->touchscreen_calibration_in_progress = false;	  
	  d->touchscreen_x_gain    = touchscreen_x_gain;
	  d->touchscreen_y_gain    = touchscreen_y_gain;
	  d->touchscreen_x_offset  = touchscreen_x_offset;
	  d->touchscreen_y_offset  = touchscreen_y_offset;
	  delete this;
	  return;
	}

      point p0, p1;
      
      p0.x = match_center_x - cal_length_x;
      p1.x = match_center_x + cal_length_x;
      p0.y = match_center_y;
      p1.y = match_center_y;
      
      draw_line_horizontal(p0, p1, WHITE);
	  
      p0.x = match_center_x;
      p1.x = match_center_x;
      p0.y = match_center_y - cal_length_y;
      p1.y = match_center_y + cal_length_y;
      
      draw_line_vertical(p0, p1, WHITE);

      p0.x = 0;
      p1.x = width;
      p0.y = last_y;
      p1.y = last_y;
      
      draw_line_horizontal(p0, p1, match_color);
      
      p0.x = last_x;
      p1.x = last_x;
      p0.y = 0;
      p1.y = height;
      draw_line_vertical(p0, p1, match_color);
    }
}


touchscreen_calibration::touchscreen_calibration(local_display* d) : window(BLACK)
{
  this->d      = d;
  blink_count  = 0;
  blink_on     = false;
  ratio        = 1;

  last_count   = 0;
  cal_step     = 0;

  last_me_x    = -100000;
  last_me_y    = -100000;

  touchscreen_x_gain    = 1.0;
  touchscreen_y_gain    = 1.0;
  touchscreen_x_offset  = 0.0;
  touchscreen_y_offset  = 0.0;
}


touchscreen_calibration::~touchscreen_calibration()
{
  release_events();
  d->mark_layout_dirty();
}




