/*
 * input map code
 *
 * Copyright 2003 Jacob Robbins
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <poll.h>
#include <alsa/asoundlib.h>

#include "../include.h"


static snd_rawmidi_t*  handle_in;





void little_callback_test_1(void* target_object, int target_index, void* source_event, size_t source_offset){
  printf("CALLBK A (pitch=%d)   ",((my_midi_event_t*)source_event)->data1);
}

void little_callback_test_2(void* target_object, int target_index, void* source_event, size_t source_offset){
  printf("CALLBK B (velocity=%d)   ",((my_midi_event_t*)source_event)->data2);
}

void little_callback_test_3(void* target_object, int target_index, void* source_event, size_t source_offset){
  printf("HARD HIT!!   ");
}



/*test the input map object's functionality using live input from a rawmidi device*/

int main(int argc, char** argv){
  unsigned char uch;
  char ch,ch2;
  int i,j,ret,disp;
  event_map_action_t* act;
  event_submap_t* sbmap;
  event_input_map_t* local_input_map;
  my_midi_event_t local_ev;
  input_map_callback_t  cbarr[3];
  cbarr[0] = little_callback_test_1;
  cbarr[1] = little_callback_test_2;
  cbarr[2] = little_callback_test_3;

  if (argc < 2){
    printf("\n useage: rawmtest alsa_rawmidi_device_name\n\n");
    printf("                                    (ex: hw:0,0 hw:1,0  .asoundrc-alias-name ...)\n\n");
    exit(0);
  }

  printf("\n\n\n testing the input map object using input from alsa rawmidi ...\n\n");


  /*Open rawmidi device*/
  printf("\nopening alsa device: %s\n\n",argv[1]);
  if ((ret = snd_rawmidi_open(&handle_in, NULL, argv[1] , 0))<0){
    printf("\nseems we have error opening rawmidi port\n");
    printf("error:%s\n",snd_strerror(ret));
    exit(-2);
  }


  
  /*Create local input map*/

  if (!(local_input_map =  event_input_map_create())){
    printf("could not make an input map, aborting\n");
    exit(3);
  }

  event_input_map_set_event_type(local_input_map, 2);

  printf("\n made input map with event type: %d  ", event_input_map_get_event_type(local_input_map));
  printf("and owner object %p\n",event_input_map_get_owner_object(local_input_map));
  print_input_map(local_input_map);





  /*make submaps*/
    
  i = EVENT_PARAMETER_DATA_TYPE_UCHAR;
  printf("\n\n inserting a submap at position 0 w/ data type %d, test type range\n",i);
  if ((event_input_map_insert_submap(local_input_map,0,EVENT_PARAMETER_DATA_TYPE_UCHAR,SUBMAP_TEST_TYPE_RANGE))<0) {
    printf("could not insert submap, aborting\n");
    exit(3);
  }

  i = EVENT_PARAMETER_DATA_TYPE_UCHAR;
  printf("\n\n inserting a submap at position 1 w/ data type %d\n",i);
  if ((event_input_map_insert_submap(local_input_map,1,EVENT_PARAMETER_DATA_TYPE_UCHAR,SUBMAP_TEST_TYPE_RANGE))<0) {
    printf("could not insert submap, aborting\n");
    exit(3);
  }
  print_input_map(local_input_map);

  

  
  /*configure submaps*/


  /*Submap 0*/
  /*modify first submap*/
  printf("\n\n configuring first submap\n");
  sbmap = event_input_map_get_submap(local_input_map, 0);

  /*first submap tests pitch (data1)*/
  event_submap_set_parameter_offset(sbmap, (&local_ev.data1 - &local_ev.status));
  printf("Set offset to %d\n",event_submap_get_parameter_offset(sbmap));

  /*make tests for first submap*/
  ch = 0; ch2 = 64;
  event_submap_append_test(sbmap,(void*)&ch,(void*)&ch2);
  ch = 65; ch2 = 100;
  event_submap_append_test(sbmap,(void*)&ch,(void*)&ch2);
  ch = 101; ch2 = 127;
  event_submap_append_test(sbmap,(void*)&ch,(void*)&ch2);
  print_input_map(local_input_map);

  /*add actions to first submap's tests*/
  printf("\n\n adding actions to first submap's tests\n");
  /*test 0*/
  act = event_submap_append_test_action(sbmap, 0);
  event_map_action_set_type(act, EVENT_MAP_ACTION_TYPE_CALLBACK_FUNCTION);
  act = event_submap_append_test_action(sbmap, 0);
  event_map_action_set_type(act, EVENT_MAP_ACTION_TYPE_REMAP_LOCAL);
  event_map_action_set_target_index(act,1);
  /*test 1*/
  act = event_submap_append_test_action(sbmap, 1);
  event_map_action_set_type(act, EVENT_MAP_ACTION_TYPE_CALLBACK_FUNCTION);
  act = event_submap_append_test_action(sbmap, 1);
  event_map_action_set_type(act, EVENT_MAP_ACTION_TYPE_CALLBACK_FUNCTION);
  event_map_action_set_function_index(act,1);
  act = event_submap_append_test_action(sbmap, 1);
  event_map_action_set_type(act, EVENT_MAP_ACTION_TYPE_REMAP_LOCAL);
  event_map_action_set_target_index(act,1);
  print_input_map(local_input_map);




  /*Submap 1*/
  /*modify second submap*/
  printf("\n\n modifying second submap\n");
  sbmap = event_input_map_get_submap(local_input_map, 1);

  /*second submap tests velocity (data2)*/
  event_submap_set_parameter_offset(sbmap, (&local_ev.data2 - &local_ev.status));
  printf("Set offset to %d\n",event_submap_get_parameter_offset(sbmap));

  /*make test for second submap*/
  ch = 70; ch2 = 127;
  event_submap_append_test(sbmap,(void*)&ch,(void*)&ch2);

  /*add actions to second submap's test*/
  printf("\n\n adding actions to second submap's test\n");
  act = event_submap_append_test_action(sbmap, 0);
  event_map_action_set_type(act, EVENT_MAP_ACTION_TYPE_CALLBACK_FUNCTION);
  event_map_action_set_function_index(act,2);
  print_input_map(local_input_map);





  /********************LOOP ON RAWMIDI INPUT***********************/

  ret=1;
  disp=0;
  i=0;
  while(1){
 
    snd_rawmidi_read(handle_in, &uch, 1);


    /*NOTE: the following is an _INCOMPLETE_ MIDI event parsing */
    /*NOTE: noteable failures of this code loop include SYSEX, MTC and more*/

    if (uch != 254)
      if (uch >> 7){
	
	local_ev.status = uch;
	ret = 2;
	if (uch > 245) disp=1;
    
      }else if (ret == 2){
    
	local_ev.data1 = uch;
	if ((local_ev.status > 191)&&(local_ev.status < 224)) disp = 1;
	else ret = 3;
    
      }else if (ret == 3){

	local_ev.data2 = uch;
	disp = 1;
    
      }
   
    if (disp){

      /****ROUTE EVENT FUNCTION HANDLES RUNNING AN EVENT THROUGH INPUT MAPS****/
      route_event(&local_ev, &local_input_map, 1, 0, cbarr, 2);

      printf("\n"); /*must print a newline to flush data to screen*/
      disp= 0;
      ret = 2;
    }
  
    
  }


  /********************END OF RAWMIDI LOOP*************************/



  /*free alsa device*/
  printf("\nclosing device: %s\n",argv[1]);
  snd_rawmidi_drain(handle_in);
  snd_rawmidi_close(handle_in);

  /*deallocate local input map*/
  printf("\n\ncleaning up\n");
  event_input_map_destroy(local_input_map);
  printf("\n\ndone \n\n");
  return 0;
}



