/* Complete static GeoJSON scene example. Link against the matching sqs_map library. */
#include "sqs_map.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static uint64_t map;
static void check(int32_t status) {if(status){fprintf(stderr,"%s\n",sqsm_map_last_error());if(map)sqsm_map_destroy(map);exit(1);}}
typedef int32_t (*json_call)(uint64_t,const uint8_t*,uint64_t,sqsm_map_bytes_t*);
static sqsm_map_bytes_t call(json_call fn,const char *request) {sqsm_map_bytes_t out={0};check(fn(map,(const uint8_t*)request,strlen(request),&out));return out;}
static void discard(json_call fn,const char *request) {sqsm_map_bytes_t out=call(fn,request);check(sqsm_map_bytes_free(out.allocation));}
/* IDs are controlled here; instances are opaque ASCII strings issued by the core.
 * Production integrations should use their existing JSON parser and serializer. */
static void instance(sqsm_map_bytes_t out,const char *key,char *value,size_t size) {
 char json[65537];if(out.len>=sizeof(json))exit(2);memcpy(json,out.data,(size_t)out.len);json[out.len]=0;
 char needle[80];snprintf(needle,sizeof(needle),"\"%s\":\"",key);const char *start=strstr(json,needle);if(!start)exit(2);start+=strlen(needle);
 const char *end=strchr(start,'"');if(!end||(size_t)(end-start)>=size)exit(2);memcpy(value,start,(size_t)(end-start));value[end-start]=0;
 for(const char *c=value;*c;c++)if(!((*c>='0'&&*c<='9')||(*c>='a'&&*c<='z')||(*c>='A'&&*c<='Z')||*c=='-'||*c==':'))exit(2);
 check(sqsm_map_bytes_free(out.allocation));
}
static void frame(int visible) {
 sqsm_map_bytes_t out={0};check(sqsm_map_render_rgba(map,&out));uint64_t red=0;
 for(uint64_t i=0;i+3<out.len;i+=4)if(out.data[i]>100&&out.data[i+1]<40&&out.data[i+2]<40)red++;
 check(sqsm_map_bytes_free(out.allocation));if((red>0)!=visible){fprintf(stderr,"Unexpected scene visibility\n");exit(3);}
}
int main(void) {
 check(sqsm_map_create(128,96,&map));char scene[200],source[200],owner[400],request[1400];
 instance(call(sqsm_map_scene_json,"{\"method\":\"create\",\"args\":[{\"id\":\"scene\"}]}"),"sceneInstanceId",scene,sizeof(scene));
 instance(call(sqsm_map_source_json,"{\"method\":\"addSource\",\"args\":[\"data\",{\"type\":\"geojson\",\"attribution\":\"Example data\",\"data\":{\"type\":\"FeatureCollection\",\"features\":[{\"type\":\"Feature\",\"id\":1,\"properties\":{},\"geometry\":{\"type\":\"Point\",\"coordinates\":[0,0]}}]}}]}"),"sourceInstanceId",source,sizeof(source));
 snprintf(owner,sizeof(owner),"{\"id\":\"scene\",\"sceneInstanceId\":\"%s\"}",scene);
 snprintf(request,sizeof(request),"{\"method\":\"attachSource\",\"args\":[%s,{\"id\":\"data\",\"sourceInstanceId\":\"%s\"}]}",owner,source);discard(sqsm_map_scene_json,request);
 discard(sqsm_map_camera_json,"{\"method\":\"jumpTo\",\"args\":[{\"center\":[0,0],\"zoom\":12}]}");
 discard(sqsm_map_layer_json,"{\"method\":\"addLayer\",\"args\":[{\"id\":\"points\",\"type\":\"circle\",\"source\":\"data\",\"paint\":{\"circle-color\":\"#ff0000\",\"circle-radius\":8}}]}");frame(0);
 const char *methods[]={"start","pause","resume","stop"};const int visible[]={1,1,1,0};
 for(size_t i=0;i<4;i++){snprintf(request,sizeof(request),"{\"method\":\"%s\",\"args\":[%s]}",methods[i],owner);discard(sqsm_map_scene_json,request);frame(visible[i]);}
 snprintf(request,sizeof(request),"{\"method\":\"detachSource\",\"args\":[%s,{\"id\":\"data\",\"sourceInstanceId\":\"%s\"}]}",owner,source);discard(sqsm_map_scene_json,request);frame(1);
 snprintf(request,sizeof(request),"{\"method\":\"remove\",\"args\":[%s]}",owner);discard(sqsm_map_scene_json,request);
 discard(sqsm_map_layer_json,"{\"method\":\"removeLayer\",\"args\":[\"points\"]}");discard(sqsm_map_source_json,"{\"method\":\"removeSource\",\"args\":[\"data\"]}");
 sqsm_map_bytes_t events={0};check(sqsm_map_poll_events_json(map,&events));check(sqsm_map_bytes_free(events.allocation));check(sqsm_map_destroy(map));map=0;
 puts("C static scene source lifecycle and real visibility: passed");return 0;
}
