2020-05-05 09:42:02 +00:00
# include <stdlib.h>
# include <string.h>
# include <sqlite3.h>
# include <cJSON.h>
# include <logger.h>
# include <database.h>
# include <models/schedule.h>
# include <models/junction_tag.h>
# include <models/tag.h>
static int
db_update_insert ( schedule_t * schedule , sqlite3_stmt * stmt )
{
int rc ;
uint16_t * periods_blob = schedule_periods_to_blob ( schedule ) ;
int blob_size = ( int ) sizeof ( uint16_t ) * ( ( periods_blob [ 0 ] * 2 ) + 1 ) ;
sqlite3_bind_int ( stmt , 1 , schedule - > id ) ;
sqlite3_bind_blob ( stmt , 2 , schedule - > uid , sizeof ( uuid_t ) , SQLITE_STATIC ) ;
sqlite3_bind_text ( stmt , 3 , schedule - > name , - 1 , SQLITE_STATIC ) ;
sqlite3_bind_blob ( stmt , 4 , periods_blob , blob_size , SQLITE_STATIC ) ;
rc = sqlite3_step ( stmt ) ;
sqlite3_finalize ( stmt ) ;
free ( periods_blob ) ;
return rc ! = SQLITE_DONE ;
}
static schedule_t *
schedule_db_select_mapper ( sqlite3_stmt * stmt )
{
const uint16_t * periods_blob ;
schedule_t * new_schedule = malloc ( sizeof ( schedule_t ) ) ;
for ( int i = 0 ; i < sqlite3_column_count ( stmt ) ; i + + )
{
const char * name = sqlite3_column_name ( stmt , i ) ;
switch ( name [ 0 ] )
{
case ' i ' : // id
new_schedule - > id = sqlite3_column_int ( stmt , i ) ;
break ;
case ' n ' : // name
strncpy ( new_schedule - > name , ( const char * ) sqlite3_column_text ( stmt , i ) , 127 ) ;
new_schedule - > name [ 127 ] = ' \0 ' ;
break ;
case ' p ' : // periods
periods_blob = sqlite3_column_blob ( stmt , i ) ;
new_schedule - > periods_count = periods_blob [ 0 ] ;
new_schedule - > periods = malloc ( sizeof ( period_t ) * periods_blob [ 0 ] ) ;
for ( int i = 0 ; i < periods_blob [ 0 ] ; + + i )
{
new_schedule - > periods [ i ] . start = periods_blob [ ( i * 2 ) + 1 ] ;
new_schedule - > periods [ i ] . end = periods_blob [ ( i * 2 ) + 2 ] ;
}
break ;
case ' u ' : // uid
uuid_copy ( new_schedule - > uid , ( const unsigned char * ) sqlite3_column_blob ( stmt , i ) ) ;
break ;
default : // ignore columns not implemented
break ;
}
}
return new_schedule ;
}
static schedule_t * *
schedule_db_select ( sqlite3_stmt * stmt )
{
schedule_t * * all_schedules = malloc ( sizeof ( schedule_t * ) ) ;
int row = 0 ;
while ( true )
{
int s ;
s = sqlite3_step ( stmt ) ;
if ( s = = SQLITE_ROW )
{
schedule_t * new_schedule = schedule_db_select_mapper ( stmt ) ;
row + + ;
all_schedules = ( schedule_t * * ) realloc ( all_schedules , sizeof ( schedule_t * ) * ( row + 1 ) ) ;
all_schedules [ row - 1 ] = new_schedule ;
}
else
{
if ( s = = SQLITE_DONE )
{
break ;
}
else
{
2020-05-05 20:29:04 +00:00
LOG_ERROR ( " error selecting schedules from database: %s \n " , sqlite3_errstr ( s ) ) ;
2020-05-05 09:42:02 +00:00
break ;
}
}
}
sqlite3_finalize ( stmt ) ;
all_schedules [ row ] = NULL ;
return all_schedules ;
}
int
schedule_save ( schedule_t * schedule )
{
sqlite3_stmt * stmt ;
if ( schedule - > id )
{
sqlite3_prepare_v2 ( global_database , " UPDATE schedules SET uid = ?2, name = ?3, periods = ?4 WHERE id=?1; " , - 1 , & stmt , NULL ) ;
}
else
{
sqlite3_prepare_v2 ( global_database , " INSERT INTO schedules(uid, name, periods) values (?2, ?3, ?4); " , - 1 , & stmt , NULL ) ;
}
int result = db_update_insert ( schedule , stmt ) ;
if ( result )
{
if ( schedule - > id )
{
LOG_ERROR ( " error inserting data: %s \n " , sqlite3_errmsg ( global_database ) ) ;
}
else
{
LOG_ERROR ( " error updating data: %s \n " , sqlite3_errmsg ( global_database ) ) ;
}
}
else
{
2020-05-11 12:50:25 +00:00
if ( ! schedule - > id )
{
schedule - > id = sqlite3_last_insert_rowid ( global_database ) ;
}
2020-05-05 09:42:02 +00:00
}
return result ;
}
2020-05-05 20:29:04 +00:00
int
schedule_remove ( schedule_t * schedule )
{
sqlite3_stmt * stmt ;
if ( ! schedule - > id )
{
return 0 ;
}
sqlite3_prepare_v2 ( global_database , " DELETE FROM schedules WHERE id=?1; " , - 1 , & stmt , NULL ) ;
sqlite3_bind_int ( stmt , 1 , schedule - > id ) ;
int rc = sqlite3_step ( stmt ) ;
sqlite3_finalize ( stmt ) ;
return rc ! = SQLITE_DONE ;
}
int
schedule_is_protected ( schedule_t * schedule )
{
uuid_t tmp_uuid ;
memset ( tmp_uuid , 0 , sizeof ( uuid_t ) ) ;
memcpy ( tmp_uuid , " off " , 3 ) ;
if ( uuid_compare ( schedule - > uid , tmp_uuid ) = = 0 )
{
return 1 ;
}
memset ( tmp_uuid , 0 , sizeof ( uuid_t ) ) ;
memcpy ( tmp_uuid , " on " , 2 ) ;
if ( uuid_compare ( schedule - > uid , tmp_uuid ) = = 0 )
{
return 1 ;
}
return 0 ;
}
2020-05-05 09:42:02 +00:00
void
schedule_free ( schedule_t * schedule )
{
free ( schedule - > periods ) ;
free ( schedule ) ;
}
void
schedule_free_list ( schedule_t * * schedules )
{
for ( int i = 0 ; schedules [ i ] ! = NULL ; + + i )
{
schedule_free ( schedules [ i ] ) ;
}
free ( schedules ) ;
}
uint16_t *
schedule_periods_to_blob ( schedule_t * schedule )
{
uint16_t * blob = malloc ( sizeof ( uint16_t ) * ( ( schedule - > periods_count * 2 ) + 1 ) ) ;
blob [ 0 ] = schedule - > periods_count ;
for ( int i = 0 ; i < schedule - > periods_count ; i + + )
{
blob [ ( i * 2 ) + 1 ] = schedule - > periods [ i ] . start ;
blob [ ( i * 2 ) + 2 ] = schedule - > periods [ i ] . end ;
}
return blob ;
}
cJSON *
schedule_to_json ( schedule_t * schedule )
{
cJSON * json = cJSON_CreateObject ( ) ;
cJSON * json_name = cJSON_CreateString ( schedule - > name ) ;
if ( json_name = = NULL )
{
cJSON_Delete ( json ) ;
return NULL ;
}
cJSON_AddItemToObject ( json , " name " , json_name ) ;
char uuid_str [ UUID_STR_LEN ] ;
schedule_uid_unparse ( schedule - > uid , uuid_str ) ;
cJSON * json_id = cJSON_CreateString ( uuid_str ) ;
if ( json_name = = NULL )
{
cJSON_Delete ( json ) ;
return NULL ;
}
cJSON_AddItemToObject ( json , " id " , json_id ) ;
cJSON * json_periods = cJSON_CreateArray ( ) ;
if ( json_periods = = NULL )
{
cJSON_Delete ( json ) ;
return NULL ;
}
cJSON_AddItemToObject ( json , " periods " , json_periods ) ;
for ( int i = 0 ; i < schedule - > periods_count ; + + i )
{
cJSON * json_period = cJSON_CreateObject ( ) ;
if ( json_period = = NULL )
{
continue ;
}
char start_str [ 8 ] , end_str [ 8 ] ;
period_t * period = & schedule - > periods [ i ] ;
sprintf ( start_str , " %02d:%02d " , period - > start / 60 , period - > start % 60 ) ;
sprintf ( end_str , " %02d:%02d " , period - > end / 60 , period - > end % 60 ) ;
cJSON * json_period_start = cJSON_CreateString ( start_str ) ;
if ( json_period_start = = NULL )
{
LOG_DEBUG ( " failed to add start period from string '%s' \n " , start_str ) ;
cJSON_Delete ( json_period ) ;
continue ;
}
cJSON_AddItemToObject ( json_period , " start " , json_period_start ) ;
cJSON * json_period_end = cJSON_CreateString ( end_str ) ;
if ( json_period_end = = NULL )
{
LOG_DEBUG ( " failed to add end period from string '%s' \n " , end_str ) ;
cJSON_Delete ( json_period ) ;
continue ;
}
cJSON_AddItemToObject ( json_period , " end " , json_period_end ) ;
cJSON_AddItemToArray ( json_periods , json_period ) ;
}
cJSON * json_tags = cJSON_CreateArray ( ) ;
int * tags_ids = junction_tag_get_tags_for_schedule_id ( schedule - > id ) ;
if ( tags_ids ! = NULL )
{
for ( int i = 0 ; tags_ids [ i ] ! = 0 ; + + i )
{
char * tag = tag_get_tag ( tags_ids [ i ] ) ;
if ( tag = = NULL )
{
continue ;
}
cJSON * json_tag = cJSON_CreateString ( tag ) ;
if ( json_tag = = NULL )
{
LOG_DEBUG ( " failed to add tag from string '%s' \n " , tag ) ;
free ( tag ) ;
continue ;
}
cJSON_AddItemToArray ( json_tags , json_tag ) ;
free ( tag ) ;
}
free ( tags_ids ) ;
}
cJSON_AddItemToObject ( json , " tags " , json_tags ) ;
return json ;
}
2020-05-05 23:05:36 +00:00
schedule_t *
schedule_get_by_id_or_off ( int id )
{
sqlite3_stmt * stmt ;
sqlite3_prepare_v2 ( global_database , " SELECT * FROM schedules WHERE id = ?1; " , - 1 , & stmt , NULL ) ;
sqlite3_bind_int ( stmt , 1 , id ) ;
schedule_t * * sql_result = schedule_db_select ( stmt ) ;
schedule_t * result = sql_result [ 0 ] ;
free ( sql_result ) ;
if ( result )
{
return result ;
}
uuid_t tmp_uuid ;
memset ( tmp_uuid , 0 , sizeof ( uuid_t ) ) ;
memcpy ( tmp_uuid , " off " , 3 ) ;
return schedule_get_by_uid ( tmp_uuid ) ;
}
2020-05-05 20:29:04 +00:00
schedule_t *
schedule_get_by_id ( int id )
{
sqlite3_stmt * stmt ;
sqlite3_prepare_v2 ( global_database , " SELECT * FROM schedules WHERE id = ?1; " , - 1 , & stmt , NULL ) ;
sqlite3_bind_int ( stmt , 1 , id ) ;
schedule_t * * sql_result = schedule_db_select ( stmt ) ;
schedule_t * result = sql_result [ 0 ] ;
free ( sql_result ) ;
return result ;
}
2020-05-06 20:49:22 +00:00
schedule_t *
schedule_get_by_uid_or_off ( uuid_t uid )
{
sqlite3_stmt * stmt ;
sqlite3_prepare_v2 ( global_database , " SELECT * FROM schedules WHERE uid = ?1; " , - 1 , & stmt , NULL ) ;
sqlite3_bind_blob ( stmt , 1 , uid , sizeof ( uuid_t ) , SQLITE_STATIC ) ;
schedule_t * * sql_result = schedule_db_select ( stmt ) ;
schedule_t * result = sql_result [ 0 ] ;
free ( sql_result ) ;
if ( result )
{
return result ;
}
uuid_t tmp_uuid ;
memset ( tmp_uuid , 0 , sizeof ( uuid_t ) ) ;
memcpy ( tmp_uuid , " off " , 3 ) ;
return schedule_get_by_uid ( tmp_uuid ) ;
}
2020-05-05 20:29:04 +00:00
schedule_t *
schedule_get_by_uid ( uuid_t uid )
{
sqlite3_stmt * stmt ;
sqlite3_prepare_v2 ( global_database , " SELECT * FROM schedules WHERE uid = ?1; " , - 1 , & stmt , NULL ) ;
sqlite3_bind_blob ( stmt , 1 , uid , sizeof ( uuid_t ) , SQLITE_STATIC ) ;
schedule_t * * sql_result = schedule_db_select ( stmt ) ;
schedule_t * result = sql_result [ 0 ] ;
free ( sql_result ) ;
return result ;
}
2020-05-19 22:51:16 +00:00
schedule_t * *
schedule_get_relay_weekdays ( int relay_id )
{
sqlite3_stmt * stmt ;
sqlite3_prepare_v2 ( global_database , " SELECT schedules.* FROM schedules INNER JOIN junction_relay_schedule ON schedules.id == junction_relay_schedule.schedule_id WHERE junction_relay_schedule.relay_id = ?1 ORDER BY junction_relay_schedule.weekday ASC " , - 1 , & stmt , NULL ) ;
sqlite3_bind_int ( stmt , 1 , relay_id ) ;
return schedule_db_select ( stmt ) ;
}
2020-05-05 09:42:02 +00:00
schedule_t * *
schedule_get_all ( )
{
sqlite3_stmt * stmt ;
sqlite3_prepare_v2 ( global_database , " SELECT * FROM schedules; " , - 1 , & stmt , NULL ) ;
return schedule_db_select ( stmt ) ;
}
int
schedule_uid_parse ( const char * uid_str , uuid_t result )
{
if ( strcmp ( " off " , uid_str ) = = 0 )
{
memset ( result , 0 , sizeof ( uuid_t ) ) ;
memcpy ( result , " off " , 3 ) ;
return 0 ;
}
if ( strcmp ( " on " , uid_str ) = = 0 )
{
memset ( result , 0 , sizeof ( uuid_t ) ) ;
memcpy ( result , " on " , 2 ) ;
return 0 ;
}
if ( uuid_parse ( uid_str , result ) )
{
return 1 ;
}
return 0 ;
}
void
schedule_uid_unparse ( const uuid_t uid , char * result )
{
uuid_t tmp_uuid ;
memset ( tmp_uuid , 0 , sizeof ( uuid_t ) ) ;
memcpy ( tmp_uuid , " off " , 3 ) ;
if ( uuid_compare ( uid , tmp_uuid ) = = 0 )
{
strcpy ( result , " off " ) ;
return ;
}
memset ( tmp_uuid , 0 , sizeof ( uuid_t ) ) ;
memcpy ( tmp_uuid , " on " , 2 ) ;
if ( uuid_compare ( uid , tmp_uuid ) = = 0 )
{
strcpy ( result , " on " ) ;
return ;
}
uuid_unparse ( uid , result ) ;
}