/branches/3.2/src/manhat-lib/shared_survey_bar_graph.c

# · C · 815 lines · 626 code · 187 blank · 2 comment · 123 complexity · a7b75e32d96984313f14653be3366039 MD5 · raw file

  1. #include <stdio.h>
  2. #include "../global.h"
  3. #include "shared_survey_bar_graph.h"
  4. #include "shared_survey_string.h"
  5. #include "shared_survey_util.h"
  6. #include "shared_survey_xml_parser.h"
  7. #include "shared_record_parser.h"
  8. double likert_total =0;
  9. double likert_count=0;
  10. static int
  11. contains_empty_response(RESULT *one_result)
  12. {
  13. VALUE_COUNT *ptr;
  14. for(ptr = one_result->value_head; ptr; ptr = ptr->next)
  15. if(atoi(ptr->value) == -1)
  16. return 1;
  17. return 0;
  18. }
  19. static void
  20. nl_to_space(char *string)
  21. {
  22. char *ptr;
  23. for(ptr=string; *ptr; ptr++)
  24. if( (*ptr==10) || (*ptr == 13) || *ptr == '\'' || *ptr == '\"')
  25. *ptr = ' ';
  26. }
  27. void replace_quotes(char *str)
  28. {
  29. int i, len;
  30. len = strlen(str);
  31. for(i = 0; i<len; i++)
  32. {
  33. if(str[i] == '\"' || str[i] == '\'')
  34. str[i] = ' ';
  35. }
  36. }
  37. static
  38. void set_likert_choice_common_values(SURVEY_DATA *data, int question_number, int steps, char *question_type, int bar_graph_count)
  39. {
  40. #define MAX_TMP_NAME 50
  41. char name[MAX_TMP_NAME];
  42. snprintf(name, MAX_TMP_NAME, "survey.question.%d.type", bar_graph_count);
  43. cs_set_value(name, question_type);
  44. nl_to_space(data->caption);
  45. snprintf(name, MAX_TMP_NAME, "survey.question.%d.title", bar_graph_count);
  46. cs_set_value(name, data->caption);
  47. snprintf(name, MAX_TMP_NAME, "survey.question.%d.question_number", bar_graph_count);
  48. cs_set_int_value(name, question_number);
  49. #undef MAX_TMP_NAME
  50. }
  51. static void
  52. set_likert_values(SURVEY_DATA *likert, RESULT *one_result, int question_number, int bar_graph_count)
  53. {
  54. #define MAX_TMP_NAME 50
  55. int i;
  56. int steps;
  57. char name[MAX_TMP_NAME];
  58. char tmp_value[MAX_TMP_NAME];
  59. int has_empty_responses = contains_empty_response(one_result);
  60. double average = 0;
  61. double total =0;
  62. int count = 0;
  63. steps = atoi(likert->steps_bgcolor);
  64. set_likert_choice_common_values(likert, question_number, steps, "likert", bar_graph_count);
  65. one_result->value_current = one_result->value_head;
  66. if(has_empty_responses)
  67. one_result->value_current = one_result->value_current->next;
  68. for(i =1; i<=steps; i++)
  69. {
  70. snprintf(name, MAX_TMP_NAME, "survey.question.%d.percent.%d", bar_graph_count, i-1);
  71. if(one_result->value_current && atoi(one_result->value_current->value)==i)
  72. {
  73. snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", (float)one_result->value_current->count/(float)one_result->count*100.0);
  74. cs_set_value(name, tmp_value);
  75. one_result->value_current = one_result->value_current->next;
  76. }
  77. else
  78. {
  79. snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", 0.0);
  80. cs_set_value(name, tmp_value);
  81. }
  82. }
  83. if(has_empty_responses)
  84. {
  85. snprintf(name, MAX_TMP_NAME, "survey.question.%d.percent.%d", bar_graph_count, i-1);
  86. one_result->value_current = one_result->value_head;
  87. snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", (float)one_result->value_current->count/(float)one_result->count*100.0);
  88. cs_set_value(name, tmp_value);
  89. }
  90. snprintf(name, MAX_TMP_NAME, "survey.question.%d.number_choices", bar_graph_count);
  91. cs_set_int_value(name, has_empty_responses ? i: i-1);
  92. for(i =1; i<=steps; i++)
  93. {
  94. snprintf(name, MAX_TMP_NAME, "survey.question.%d.XScale.%d", bar_graph_count, i-1);
  95. cs_set_int_value(name, i);
  96. }
  97. if(has_empty_responses)
  98. {
  99. snprintf(name, MAX_TMP_NAME, "survey.question.%d.XScale.%d", bar_graph_count, i-1);
  100. cs_set_int_value(name, -1);
  101. }
  102. for(i = 0; i<steps; i++)
  103. {
  104. char temp[MAX_PATH +1];
  105. snprintf(name, MAX_TMP_NAME, "survey.question.%d.legend.%d", bar_graph_count, i);
  106. if(i == steps -1)
  107. {
  108. nl_to_space(likert->right_rows);
  109. snprintf(temp, MAX_PATH +1, "%s %d", likert->right_rows, i+1);
  110. cs_set_value(name, temp);
  111. }
  112. else if(i == 0)
  113. {
  114. nl_to_space(likert->left_cols);
  115. snprintf(temp, MAX_PATH +1, "%s %d", likert->left_cols, i+1);
  116. cs_set_value(name, temp);
  117. }
  118. else
  119. {
  120. snprintf(temp, MAX_PATH +1, "%d", i+1);
  121. cs_set_value(name, temp);
  122. }
  123. }
  124. if(has_empty_responses)
  125. {
  126. snprintf(name, MAX_TMP_NAME, "survey.question.%d.noanswer", bar_graph_count);
  127. cs_set_int_value(name, 1);
  128. }
  129. one_result->value_current = one_result->value_head;
  130. if(has_empty_responses)
  131. one_result->value_current = one_result->value_current->next;
  132. for(i =1; i<=steps; i++)
  133. {
  134. snprintf(name, MAX_TMP_NAME, "survey.question.%d.count.%d", bar_graph_count, i-1);
  135. if(one_result->value_current && atoi(one_result->value_current->value)==i)
  136. {
  137. cs_set_int_value(name, one_result->value_current->count);
  138. total += i * one_result->value_current->count;
  139. count += one_result->value_current->count;
  140. one_result->value_current = one_result->value_current->next;
  141. }
  142. else
  143. cs_set_int_value(name, 0);
  144. }
  145. if(count > 0)
  146. average = total / count;
  147. likert_total += average;
  148. likert_count++;
  149. if(has_empty_responses)
  150. {
  151. snprintf(name, MAX_TMP_NAME, "survey.question.%d.count.%d", bar_graph_count, i-1);
  152. one_result->value_current = one_result->value_head;
  153. cs_set_int_value(name, one_result->value_current->count);
  154. }
  155. #undef MAX_TMP_NAME
  156. }
  157. static int
  158. get_choice_count(SURVEY_DATA *choice)
  159. {
  160. int i = 0;
  161. choice->current = choice->head;
  162. while(choice->current)
  163. {
  164. i++;
  165. choice->current = choice->current->next;
  166. }
  167. return i;
  168. }
  169. static void
  170. set_choice_values(SURVEY_DATA *choice, RESULT *one_result, int question_number, int bar_graph_count )
  171. {
  172. #define MAX_TMP_NAME 100
  173. int i =1;
  174. int has_empty_responses = contains_empty_response(one_result);
  175. int flag = get_choice_count(choice);
  176. char name[MAX_TMP_NAME];
  177. char tmp_value[MAX_TMP_NAME];
  178. if(strcmp(choice->steps_bgcolor, "yes") ==0)
  179. {
  180. snprintf(name, MAX_TMP_NAME, "survey.question.%d.multi", bar_graph_count);
  181. cs_set_int_value(name, 1);
  182. }
  183. set_likert_choice_common_values(choice, question_number, flag, "multi_choice", bar_graph_count);
  184. one_result->value_current = one_result->value_head;
  185. if(has_empty_responses)
  186. one_result->value_current = one_result->value_current->next;
  187. choice->current = choice->head;
  188. while(choice->current )
  189. {
  190. snprintf(name, MAX_TMP_NAME, "survey.question.%d.percent.%d", bar_graph_count, i-1);
  191. if(one_result->value_current && (atoi(one_result->value_current->value) == i))
  192. {
  193. snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", ((float)one_result->value_current->count/(float)one_result->count) * 100.0);
  194. cs_set_value(name, tmp_value);
  195. one_result->value_current = one_result->value_current->next;
  196. }
  197. else
  198. {
  199. snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", 0.0);
  200. cs_set_value(name, tmp_value);
  201. }
  202. i++;
  203. choice->current = choice->current->next;
  204. }
  205. if(has_empty_responses)
  206. {
  207. snprintf(name, MAX_TMP_NAME, "survey.question.%d.percent.%d", bar_graph_count, i-1);
  208. one_result->value_current = one_result->value_head;
  209. snprintf(tmp_value, MAX_TMP_NAME, "%3.1f", ((float)one_result->value_current->count/(float)one_result->count) * 100.0);
  210. cs_set_value(name, tmp_value);
  211. }
  212. snprintf(name, MAX_TMP_NAME, "survey.question.%d.number_choices", bar_graph_count);
  213. cs_set_int_value(name, has_empty_responses ? i: i-1);
  214. for(i =1; i<=flag; i++)
  215. {
  216. snprintf(name, MAX_TMP_NAME, "survey.question.%d.XScale.%d", bar_graph_count, i-1);
  217. cs_set_int_value(name, i);
  218. }
  219. if(has_empty_responses)
  220. {
  221. snprintf(name, MAX_TMP_NAME, "survey.question.%d.XScale.%d", bar_graph_count, i-1);
  222. cs_set_int_value(name, -1);
  223. }
  224. i = 1;
  225. choice->current = choice->head;
  226. while(choice->current )
  227. {
  228. snprintf(name, MAX_TMP_NAME, "survey.question.%d.legend.%d", bar_graph_count, i-1);
  229. nl_to_space(choice->current->choice);
  230. cs_set_value(name, choice->current->choice);
  231. i++;
  232. choice->current = choice->current->next;
  233. }
  234. if(has_empty_responses)
  235. {
  236. snprintf(name, MAX_TMP_NAME, "survey.question.%d.noanswer", bar_graph_count);
  237. cs_set_int_value(name, 1);
  238. }
  239. one_result->value_current = one_result->value_head;
  240. if(has_empty_responses)
  241. one_result->value_current = one_result->value_current->next;
  242. choice->current = choice->head;
  243. i =1;
  244. while(choice->current )
  245. {
  246. snprintf(name, MAX_TMP_NAME, "survey.question.%d.count.%d", bar_graph_count, i-1);
  247. if(one_result->value_current && atoi(one_result->value_current->value) == i)
  248. {
  249. cs_set_int_value(name, one_result->value_current->count);
  250. one_result->value_current = one_result->value_current->next;
  251. }
  252. else
  253. cs_set_int_value(name, 0);
  254. i++;
  255. choice->current = choice->current->next;
  256. }
  257. if(has_empty_responses)
  258. {
  259. snprintf(name, MAX_TMP_NAME, "survey.question.%d.count.%d", bar_graph_count, i-1);
  260. one_result->value_current = one_result->value_head;
  261. cs_set_int_value(name, one_result->value_current->count);
  262. }
  263. #undef MAX_TMP_NAME
  264. }
  265. static void
  266. set_memo_values(SURVEY_DATA *memo, RESULT *one_result, int question_number, char *question_type, int element_number)
  267. {
  268. #define MAX_TMP_NAME 50
  269. char name[MAX_TMP_NAME];
  270. int i =0;
  271. snprintf(name, MAX_TMP_NAME, "survey.question.%d.type", element_number);
  272. cs_set_value(name, question_type );
  273. snprintf(name, MAX_TMP_NAME, "survey.question.%d.title", element_number);
  274. cs_set_value(name, memo->caption);
  275. snprintf(name, MAX_TMP_NAME, "survey.question.%d.question_number", element_number);
  276. cs_set_int_value(name, question_number);
  277. one_result->value_current = one_result->value_head;
  278. while(one_result->value_current)
  279. {
  280. if(strcmp(one_result->value_current->value, "-1") == 0)
  281. {
  282. snprintf(name, MAX_TMP_NAME, "survey.question.%d.no_count", element_number);
  283. cs_set_int_value(name, one_result->value_current->count);
  284. }
  285. else
  286. {
  287. snprintf(name, MAX_TMP_NAME, "survey.question.%d.answer.%d", element_number, i);
  288. cs_set_value(name, one_result->value_current->value);
  289. snprintf(name, MAX_TMP_NAME, "survey.question.%d.count.%d", element_number, i);
  290. cs_set_int_value(name, one_result->value_current->count);
  291. i++;
  292. }
  293. one_result->value_current = one_result->value_current->next;
  294. }
  295. #undef MAX_TMP_NAME
  296. }
  297. static RESULT *
  298. get_one_result(RECORD *list, int id)
  299. {
  300. RESULT *ptr;
  301. ptr = list->head;
  302. while(ptr)
  303. {
  304. if(ptr->id == id )
  305. return ptr;
  306. ptr = ptr->next;
  307. }
  308. return 0;
  309. }
  310. static int value_cmp(const char *a, const char *b)
  311. {
  312. int value_a, value_b;
  313. if(!strcmp(a,b))
  314. return 0;
  315. if(!strcmp(a, "-1"))
  316. return -1;
  317. if(!strcmp(b,"-1"))
  318. return 1;
  319. value_a = atoi(a);
  320. value_b = atoi(b);
  321. if(value_a >value_b)
  322. return 1;
  323. return -1;
  324. }
  325. static RESULT *
  326. sort_one_result(RESULT *one)
  327. {
  328. VALUE_COUNT *q, *tail, *p, *r;
  329. if (one->value_head != NULL)
  330. {
  331. tail = one->value_head;
  332. while (tail->next)
  333. {
  334. q = tail->next;
  335. if (value_cmp (q->value, one->value_head->value) < 0)
  336. {
  337. tail->next = q->next;
  338. q->next = one->value_head;
  339. one->value_head = q;
  340. }
  341. else
  342. {
  343. r = one->value_head;
  344. p = r->next;
  345. while (value_cmp (q->value, p->value) > 0)
  346. {
  347. r = p;
  348. p = r->next;
  349. }
  350. if (q == p)
  351. tail = q;
  352. else
  353. {
  354. tail->next = q->next;
  355. q->next = p;
  356. r->next = q;
  357. }
  358. }
  359. }
  360. }
  361. return one;
  362. }
  363. static RECORD *
  364. sort_value_list(RECORD * list)
  365. {
  366. list->current = list->head;
  367. while(list->current)
  368. {
  369. list->current = sort_one_result(list->current);
  370. list->current = list->current->next;
  371. }
  372. return list;
  373. }
  374. static void
  375. set_response_rate_title(SURVEY_DATA *data, RECORD *list, int number_takers)
  376. {
  377. float response_rate;
  378. char tmp_value[MAX_PATH +1];
  379. char server_string[MAX_PATH +1];
  380. list->current = list->head;
  381. get_server_string(server_string, MAX_PATH);
  382. cs_set_value("survey.server_string", server_string);
  383. cs_set_int_value("survey.num_response", list->current->count);
  384. /* print number of people who could have taken the survey */
  385. if(number_takers == -1)
  386. {
  387. cs_set_int_value("survey.num_expect_takers", list->expect_takers);
  388. response_rate = (float) list->current->count/list->expect_takers;
  389. }
  390. else if(number_takers > 0)
  391. {
  392. cs_set_int_value("survey.num_expect_takers", number_takers);
  393. response_rate = (float)list->current->count/number_takers;
  394. }
  395. snprintf(tmp_value, MAX_PATH +1, "%.1f%%", response_rate * 100.0);
  396. cs_set_value("survey.rate", tmp_value);
  397. cs_set_value("survey.title", data->caption);
  398. }
  399. static
  400. void set_title_element(SURVEY_LIST *list, RECORD *record_list, int number_takers)
  401. {
  402. int found = 0;
  403. for(list->current = list->head; list->current && !found; list->current=list->current->next)
  404. {
  405. found = !strcmp(list->current->tag_name, "title");
  406. if(found)
  407. set_response_rate_title(list->current, record_list, number_takers);
  408. }
  409. }
  410. static
  411. void set_bar_graphs(SURVEY_LIST *list, RECORD *record_list, int *bar_graph_count)
  412. {
  413. int question_number = 0;
  414. RESULT *ptr;
  415. double average;
  416. char temp[MAX_PATH +1];
  417. *bar_graph_count = 0;
  418. for(list->current = list->head; list->current; list->current=list->current->next)
  419. {
  420. if(strcmp(list->current->tag_name, "title") !=0 && strcmp(list->current->tag_name, "custom") != 0)
  421. question_number++;
  422. /** is_likert_tag() is in shared_survey_util.c ***/
  423. if(is_likert_tag(list->current->tag_name) ||
  424. !strcmp(list->current->tag_name, "choice") )
  425. {
  426. ptr = get_one_result(record_list, list->current->id);
  427. if(ptr)
  428. {
  429. if(is_likert_tag(list->current->tag_name))
  430. set_likert_values(list->current, ptr, question_number, *bar_graph_count);
  431. else
  432. set_choice_values(list->current, ptr, question_number, *bar_graph_count);
  433. (*bar_graph_count)++;
  434. }
  435. }
  436. }
  437. if(likert_count >0)
  438. {
  439. average = likert_total / likert_count;
  440. snprintf(temp, MAX_PATH +1, "%.4f", average);
  441. cs_set_value("survey.likert_avg_response", temp);
  442. }
  443. }
  444. static void
  445. set_text_responses(SURVEY_LIST *list, RECORD *record_list, int bar_graph_count)
  446. {
  447. int question_number = 0;
  448. RESULT *ptr;
  449. int element_number;
  450. element_number = bar_graph_count;
  451. for(list->current = list->head; list->current; list->current=list->current->next)
  452. {
  453. if(strcmp(list->current->tag_name, "title") != 0 && strcmp(list->current->tag_name, "custom") != 0)
  454. question_number++;
  455. if(!strcmp(list->current->tag_name, "memo") ||
  456. !strcmp(list->current->tag_name, "text") )
  457. {
  458. ptr = get_one_result(record_list, list->current->id);
  459. if(ptr)
  460. {
  461. set_memo_values(list->current, ptr, question_number,
  462. !strcmp(list->current->tag_name, "memo")?"memo":"short-answer",
  463. element_number);
  464. element_number++;
  465. }
  466. }
  467. }
  468. }
  469. static int find_value_in_list(VALUE_COUNT *v_head, char *temp, int count)
  470. {
  471. VALUE_COUNT *ptr;
  472. for(ptr = v_head; ptr; ptr = ptr->next)
  473. {
  474. if(strcmp(ptr->value, temp) ==0)
  475. {
  476. ptr->count = ptr->count +count;
  477. return 1;
  478. }
  479. }
  480. return 0;
  481. }
  482. static VALUE_COUNT *add_node(char *new_value, VALUE_COUNT *head, int count)
  483. {
  484. VALUE_COUNT *ptr, *current;
  485. ptr = (VALUE_COUNT *)malloc(sizeof(VALUE_COUNT));
  486. if(!ptr)
  487. cs_critical_error(ERR_MALLOC_FAILED, "shared_survey_bar_graph");
  488. ptr->value = malloc_str(new_value);
  489. ptr->count = count;
  490. ptr->next =0;
  491. if(!head)
  492. head = ptr;
  493. else
  494. {
  495. current = head;
  496. while(current->next)
  497. {
  498. current = current->next;
  499. }
  500. current->next = ptr;
  501. }
  502. return head;
  503. }
  504. static void parse_value(char *temp, char *new_value)
  505. {
  506. char *ptr;
  507. ptr = strchr(temp, '|');
  508. if(!ptr)
  509. cs_critical_error(ERR_SURVEY_PARSE_DATA_FAILED, "Shared_survey_bar_graph");
  510. *ptr = '\0';
  511. strncpy(new_value, temp, MAX_PATH +1);
  512. ptr++;
  513. strncpy(temp, ptr, MAX_PATH +1);
  514. }
  515. static int get_number_data_fields(char *temp)
  516. {
  517. int count =0, len =0, i;
  518. len = strlen(temp);
  519. for(i =0; i<len; i++)
  520. {
  521. if(temp[i] == '|')
  522. count++;
  523. }
  524. return count;
  525. }
  526. static void free_value_count(VALUE_COUNT *head)
  527. {
  528. VALUE_COUNT *ptr;
  529. while(head)
  530. {
  531. ptr = head->next;
  532. if(head->value)
  533. free(head->value);
  534. free(head);
  535. head = ptr;
  536. }
  537. }
  538. static VALUE_COUNT *get_new_value_list(VALUE_COUNT *old)
  539. {
  540. VALUE_COUNT *v_head =0, *v_ptr;
  541. char temp[MAX_PATH +1];
  542. char new_value[MAX_PATH +1];
  543. int count =0, found =0, i;
  544. for(v_ptr = old; v_ptr; v_ptr = v_ptr->next)
  545. {
  546. strncpy(temp, v_ptr->value, MAX_PATH +1);
  547. count = get_number_data_fields(temp);
  548. if(count > 1)
  549. {
  550. for(i = 0; i<count-1; i++)
  551. {
  552. found =0;
  553. parse_value(temp, new_value);
  554. if(v_head)
  555. found = find_value_in_list(v_head, new_value, v_ptr->count);
  556. if(!found)
  557. v_head = add_node(new_value, v_head, v_ptr->count);
  558. }
  559. found =0;
  560. temp[strlen(temp) -1] = '\0';
  561. if(v_head)
  562. found = find_value_in_list(v_head, temp, v_ptr->count);
  563. if(!found)
  564. v_head = add_node(temp, v_head, v_ptr->count);
  565. }
  566. else
  567. {
  568. found = 0;
  569. temp[strlen(temp)-1] = '\0';
  570. if(v_head)
  571. found = find_value_in_list(v_head, temp, v_ptr->count);
  572. if(!found)
  573. v_head = add_node(temp, v_head, v_ptr->count);
  574. }
  575. }
  576. return v_head;
  577. }
  578. RECORD * parse_multi_select_data(RECORD *re_list, int id)
  579. {
  580. RESULT *ptr;
  581. VALUE_COUNT *v_head =0;
  582. for(ptr = re_list->head; ptr; ptr = ptr->next)
  583. {
  584. if(id == ptr->id)
  585. {
  586. v_head = get_new_value_list(ptr->value_head);
  587. if(v_head)
  588. {
  589. free_value_count(ptr->value_head);
  590. ptr->value_head = v_head;
  591. }
  592. }
  593. }
  594. return re_list;
  595. }
  596. static void check_multi_choice_answers(SURVEY_LIST *list, RECORD *re_list)
  597. {
  598. SURVEY_DATA *ptr;
  599. for(ptr = list->head; ptr;ptr = ptr->next)
  600. {
  601. if(strcmp(ptr->tag_name, "choice") ==0 && strcmp(ptr->steps_bgcolor, "yes") ==0)
  602. {
  603. re_list = parse_multi_select_data(re_list, ptr->id);
  604. }
  605. }
  606. }
  607. int
  608. set_survey_graph_results( char *survey_fname, char *survey_result_fname, int number_takers)
  609. {
  610. SURVEY_LIST *list;
  611. RECORD *record_list;
  612. int results_found = 0;
  613. int bar_graph_count = 0;
  614. list = survey_data_parser(survey_fname); /* shared_survey_xml_parser.c */
  615. record_list = record_parser(survey_result_fname); /* shared_record_parser.c */
  616. if(record_list->head)
  617. {
  618. check_multi_choice_answers(list, record_list);
  619. record_list = sort_value_list(record_list);
  620. set_title_element(list, record_list, number_takers);
  621. set_bar_graphs(list,record_list, &bar_graph_count);
  622. set_text_responses(list,record_list, bar_graph_count);
  623. results_found = 1;
  624. }
  625. free_record_list(record_list);
  626. free_survey_data_list(list);
  627. return results_found;
  628. }