#include "clog.h"
#include "cgi.h"
#include "input.h"
#include "wrenchboard_api.h"
#include "reco_engine.h"  //error in file name
#include "email.h"
#include "safestring.h"
#include <string>
#include <iostream>
#include <cstdlib>
#include "pgsql.h"
#include "pgsql_wrapper.h"
#include <curl/curl.h>
#include "account.h"
#include "cards.h"
#include "twilo.h"
#include "mobile.h"
#include "jobs_manager.h"
#include "family_acc.h"
#include "common_tool.h"
#include "account.h"
#include "payments.h"

long  WrenchFamilyList(CVars in, CVars &out);
long  WrenchFamilyWallet(CVars in, CVars &out);
long  WrenchFamilyAdd(CVars in, CVars &out);
long  WrenchFamilyUpdate(CVars in, CVars &out);
long  WrenchFamilyManage(CVars in, CVars &out);
long  WrenchSampleTasks(CVars in, CVars &out);
long  WrenchSuggestTasks(CVars in, CVars &out);
long  WrenchSuggestList(CVars in, CVars &out);
long  WrenchSuggestWaitingList(CVars in, CVars &out);
long  WrenchSuggestTaskStatus(CVars in, CVars &out);
long WrenchFamilyTransferStart(CVars in, CVars &out);
long WrenchFamilyTransfer(CVars in, CVars &out);
long WrenchFamilyTransferHx(CVars in, CVars &out);
long  WrenchFamilyInvite(CVars in, CVars &out);
long  WrenchFamilyInviteList(CVars in, CVars &out);
long  WrenchRelativesKidsEdit(CVars in, CVars &out);
long  WrenchRelativesSettings(CVars in, CVars &out);
long  WrenchRelativesReminder(CVars in, CVars &out);


long family_calls(CVars in, CVars &out){
    logfmt(logINFO, "family_calls()");
    out["result"] = "YES I GET TO BACK END";
    long action = REQ_LONG(in, "action", 0, -1);
    CVars x;
    long ret = 0;
    const char * loc = getenv("REMOTE_ADDR");
    const PGresult *res;
    logfmt(logINFO, "action = %ld", action);

    switch (action) {
        case WRENCHBOARD_FAMILY_LIST:
            return WrenchFamilyList(in, out);
            break;

        case WRENCHBOARD_FAMILY_WALLET:
             return WrenchFamilyWallet(in, out);
        break;

        case WRENCHBOARD_FAMILY_TRANSFERSTART:
            return WrenchFamilyTransferStart(in, out);
        break;

        case WRENCHBOARD_FAMILY_TRANSFERHX:
             return WrenchFamilyTransferHx(in, out);
        break;

        case  WRENCHBOARD_FAMILY_TRANSFER:
             return WrenchFamilyTransfer(in, out);
        break;

        case WRENCHBOARD_FAMILY_SAMPLETASKS:
            return WrenchSampleTasks(in, out);
            break;

        case WRENCHBOARD_FAMILY_SGGESTSTATUS:
             logfmt(logINFO, "ENTER CALL long WRENCHBOARD_FAMILY_SGGESTTASKS");
             return WrenchSuggestTaskStatus(in, out);
        break;

        case WRENCHBOARD_FAMILY_ADD:
            return WrenchFamilyAdd(in, out);
            break;

        case WRENCHBOARD_FAMILY_UPDATE:
            return WrenchFamilyUpdate(in, out);
            break;

        case WRENCHBOARD_FAMILY_MANAGE:
            return WrenchFamilyManage(in, out);
            break;

        case WRENCHBOARD_FAMILY_SGGESTTASKS:
             logfmt(logINFO, "ENTER CALL long WRENCHBOARD_FAMILY_SGGESTTASKS");
               return WrenchSuggestTasks(in, out);
            break;

        case WRENCHBOARD_FAMILY_SGGESTLIST:
             logfmt(logINFO, "ENTER CALL long WRENCHBOARD_FAMILY_SGGESTLIST");
              return WrenchSuggestList(in, out);
            break;
//long  WrenchSuggestWaitingList(CVars in, CVars &out)
        case WRENCHBOARD_FAMILY_SGGESTWAITING:
             logfmt(logINFO, "ENTER CALL long WRENCHBOARD_FAMILY_SGGESTWAITING");
               return WrenchSuggestWaitingList(in, out); // this now the parent
            break;

        case WRENCHBOARD_FAMILY_RELINVITE:
             logfmt(logINFO, "ENTER CALL long WRENCHBOARD_FAMILY_RELINVITE");
             return WrenchFamilyInvite(in, out);
            break;
        case WRENCHBOARD_FAMILY_RELLIST:
             logfmt(logINFO, "ENTER CALL long WRENCHBOARD_FAMILY_RELLIST");
              return WrenchFamilyInviteList(in, out);
        break;

        case WRENCHBOARD_RELATIVES_SETTINGS:
            logfmt(logINFO, "ENTER CALL long WRENCHBOARD_RELATIVES_SETTINGS");
            return   WrenchRelativesSettings(in, out);
        break;

        case WRENCHBOARD_RELATIVES_EDITKIDS:
            logfmt(logINFO, "ENTER CALL long WRENCHBOARD_RELATIVES_SETTINGS");
             return WrenchRelativesKidsEdit(in, out);
            return 0;
        break;

         case WRENCHBOARD_RELATIVES_REMINDER:
            logfmt(logINFO, "ENTER CALL long WRENCHBOARD_RELATIVES_SETTINGS");
               return WrenchRelativesReminder(in, out);
            return 0;
         break;
    }
return 0;
}

long  WrenchRelativesReminder(CVars in, CVars &out){

  logfmt(logINFO, "ENTER CALL long WrenchRelativesReminder");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    long relative_kid_id = 0;
    const PGresult *res;
    CVars xx;

    try{
        REQ_STRING(in, "uid", 3, 150, "(.*)");
        REQ_STRING(in, "relative_uid", 3, 150, "(.*)");
        out["total_kid"] ="0";

            load_db_record(out, "SELECT id AS member_id FROM members  WHERE uid::text = '%s'  ", in["uid"].c_str());
            if ( out["member_id"].Long() > 0)
            {
                 load_db_record(out, "SELECT id AS relative_id, uid AS  relative_uid FROM members_family_relative WHERE member_id = %lu AND uid::text ='%s' ",out["member_id"].Long(), in["relative_uid"].c_str());

                 family_email(WRENCHBOARD_RELATIVES_REMINDER, out, out);

                 ret = PHP_API_OK;
                 out["status"] = "OK";
            }
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchRelativesReminder");
    }

 logfmt(logINFO, "WrenchRelativesReminder()");
 return ret;
}



long  WrenchRelativesSettings(CVars in, CVars &out){

  logfmt(logINFO, "ENTER CALL long WrenchRelativesSettings");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    long relative_kid_id = 0;
    const PGresult *res;
    CVars xx;

    try{
        REQ_STRING(in, "uid", 3, 150, "(.*)");
        REQ_STRING(in, "relative_uid", 3, 150, "(.*)");
        out["total_kid"] ="0";

            load_db_record(out, "SELECT id AS member_id FROM members  WHERE uid::text = '%s'  ", in["uid"].c_str());
            if ( out["member_id"].Long() > 0)
            {
                res = pgsql_query("SELECT * FROM family_relative_kids WHERE relative_uid::text = '%s'::text AND member_id=%lu AND add_status > 0", in["relative_uid"].c_str(),out["member_id"].Long() );
                if (res != NULL && pgsql_num_rows(res) > 0) {
                out["total_kid"] =  pgsql_num_rows(res);
                for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                            map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                            CVars rec;
                            map_to_cvars(f, rec);

                           snprintf(vname, sizeof (vname), "family_uid_%05d", i);
                           out[vname] = rec["family_uid"];
                    }
                }
                 ret = PHP_API_OK;
                 out["status"] = "OK";
            }
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchRelativesSettings");
    }

 logfmt(logINFO, "WrenchRelativesSettings()");
 return ret;
}

long  WrenchRelativesKidsEdit(CVars in, CVars &out){
  logfmt(logINFO, "ENTER CALL long WrenchRelativesKidsEdit");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    long relative_kid_id = 0;
    const PGresult *res;
    CVars xx;

    try{
        REQ_STRING(in, "uid", 3, 150, "(.*)");
        REQ_STRING(in, "relative_uid", 3, 150, "(.*)");
        REQ_STRING(in, "family_uid", 3, 150, "(.*)");
        long add = REQ_LONG(in, "add", 1, -1);

            load_db_record(out, "SELECT id AS member_id FROM members  WHERE uid::text = '%s'  ", in["uid"].c_str());
            if ( out["member_id"].Long() > 0)
            {
                load_db_record(out, "SELECT id AS relative_id, uid AS  relative_uid FROM members_family_relative WHERE member_id = %lu AND uid::text ='%s' ",out["member_id"].Long(), in["relative_uid"].c_str());
                load_db_record(out, "SELECT id AS family_id, uid AS  family_uid FROM members_family WHERE member_id = %lu AND uid::text ='%s' ",out["member_id"].Long(), in["family_uid"].c_str());

                out["relative_kid_id"] = "0";
                res = pgsql_query("SELECT id AS relative_kid_id FROM family_relative_kids WHERE relative_uid::text = '%s'::text AND family_uid::text = '%s'::text ", in["relative_uid"].c_str(), in["family_uid"].c_str() );
                if (res != NULL && pgsql_num_rows(res) > 0) {
                            map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
                            CVars rec;
                            map_to_cvars(f, rec);
                            out["relative_kid_id"] =  rec["relative_kid_id"];
                }
//                if ( load_db_record(out, "SELECT id AS relative_kid_id FROM family_relative_kids WHERE relative_uid::text = '%s'::text AND family_uid::text = '%s'::text ", in["relative_uid"].c_str(), in["family_uid"].c_str())> 0){
//                  logfmt(logINFO, "WrenchRelativesKidsEdit() Previous Kids Entry");
//                }
//                else{
//                   out["relative_kid_id"] = "0";
//                }

                if ( out["relative_id"].Long() > 0  && out["family_id"].Long() > 0 ){
                        xx["add_status"] = in["add"];
                        xx["add_status"].set_valid(true);
                          if ( out["relative_kid_id"].Long() > 0 ){
                               update_db_record(DBS_VALID, "family_relative_kids", xx, out["relative_kid_id"].Long());
                          }else{
                                  xx["member_id"] = out["member_id"];
                                  xx["member_id"].set_valid(true);
                                  xx["relative_uid"] = in["relative_uid"];
                                  xx["relative_uid"].set_valid(true);
                                  xx["family_uid"] = in["family_uid"];
                                  xx["family_uid"].set_valid(true);

                                  out["relative_kid_id"] = insert_db_record(DBS_VALID, "family_relative_kids", "family_relative_kids_id_seq", xx);
                                  if(out["relative_kid_id"].Long()  > 0  ){
                                  // load_db_record( out, "SELECT id AS suggest_id,* FROM members_family_suggesttask WHERE id = %lu ", out["suggested_task_id"].Long());
                                  //   family_email(WRENCHBOARD_FAMILY_SGGESTTASKS, out, out); //
                                  }
                          }

                     ret = PHP_API_OK;
                     out["status"] = "OK";

                }
            }

    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchRelativesKidsEdit");
    }

 logfmt(logINFO, "WrenchRelativesKidsEdit()");
 return ret;
}




long  WrenchFamilyInviteList(CVars in, CVars &out){
  logfmt(logINFO, "ENTER CALL long WrenchFamilyInviteList");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    const PGresult *res;
    try{
        long member_id = REQ_LONG(in, "member_id", 1, -1);
        long offset = REQ_LONG(in, "offset", 1, -1);
        long limit = REQ_LONG(in, "limit", 1, -1);

        out["total_record"] = "0";
        res = pgsql_query("SELECT * "
                          " FROM members_family_relative  "
                          " WHERE member_id = %lu  "
                          " AND status IN (0, 1,2,3,4,5) "
                          " ORDER BY id DESC ", member_id );

          if (res != NULL && pgsql_num_rows(res) > 0) {
              out["total_record"] = pgsql_num_rows(res);

              for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                  map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                  if (f.empty()) continue;
                  CVars rec;
                  map_to_cvars(f, rec);

                    snprintf(vname, sizeof (vname), "uid_%05d", i);
                    out[vname] = rec["uid"];

                    snprintf(vname, sizeof (vname), "firstname_%05d", i);
                    out[vname] = rec["firstname"];

                    snprintf(vname, sizeof (vname), "lastname_%05d", i);
                    out[vname] = rec["lastname"];

                    snprintf(vname, sizeof (vname), "email_%05d", i);
                    out[vname] = rec["email"];

                    snprintf(vname, sizeof (vname), "status_%05d", i);
                    out[vname] = rec["status"];

                    snprintf(vname, sizeof (vname), "family_type_%05d", i);
                    out[vname] = rec["family_type"];

              }
          }
          ret = PHP_API_OK;
          out["status"] = "OK";

    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchFamilyInviteList");
    }

 logfmt(logINFO, "WrenchFamilyInviteList()");
 return ret;
}

long  WrenchFamilyInvite(CVars in, CVars &out){
    long ret = PHP_API_BAD_PARAM;
    try{
        long member_id = REQ_LONG(in, "member_id", 1, -1);
        REQ_STRING(in, "uid", 3, 150, "(.*)");
        REQ_STRING(in, "firstname", 3, 35, "(.*)");
        REQ_STRING(in, "lastname", 3, 35, "(.*)");
        REQ_STRING(in, "email", 3, 299, "(.*)");
        REQ_STRING(in, "family_type", 3, 25, "(.*)");

        out["invite_id"] ="0";// we will set if all okay
//        const PGresult *res = pgsql_query("SELECT id FROM members_family_relative  "
//                                          " WHERE LOWER('%s') = LOWER(email) AND member_id= %lu", in["email"].c_str(), member_id);
         load_db_record(out, "SELECT count(id) AS prev_entry FROM members_family_relative  "
                                 " WHERE LOWER('%s') = LOWER(email) AND member_id= %lu", in["email"].c_str(), member_id);

          if ( out["prev_entry"].Long() ==  0)
         {
//
//                    if ( out["prev_entry"].Long()> 0){
//                               out["status_msg"] = "Duplicate";
//                               out["status_msg"] = "DUPLICATE";
//                    }
//                    else{
                                CVars xx;
                                xx["member_id"] = member_id;
                                xx["member_id"].set_valid(true);
                                xx["member_uid"] = in["uid"];
                                xx["member_uid"].set_valid(true);
                                xx["firstname"] = in["firstname"];
                                xx["firstname"].set_valid(true);
                                xx["lastname"] = in["lastname"];
                                xx["lastname"].set_valid(true);
                                xx["email"] = in["email"];
                                xx["email"].set_valid(true);
                                xx["family_type"] = in["family_type"];
                                xx["family_type"].set_valid(true);

                                out["invite_id"] = insert_db_record(DBS_VALID, "members_family_relative", "members_family_relative_id_seq", xx);
                                if(out["invite_id"].Long()  > 0  ){
                                // load_db_record( out, "SELECT id AS suggest_id,* FROM members_family_suggesttask WHERE id = %lu ", out["suggested_task_id"].Long());
                                //   family_email(WRENCHBOARD_FAMILY_SGGESTTASKS, out, out); //
                                }
                                ret = PHP_API_OK;
                                out["status"] = "OK";

               //     }


        }
        else{
           out["status_msg"] = "Duplicate";
           out["status_msg"] = "DUPLICATE";
        }
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchFamilyInvite");
    }

 logfmt(logINFO, "WrenchFamilyInvite()");
 return ret;
}

long  WrenchSuggestWaitingList(CVars in, CVars &out){ // this is the parent now
  logfmt(logINFO, "ENTER CALL long WrenchSuggestWaitingList");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    const PGresult *res;
    try{
        long member_id = REQ_LONG(in, "member_id", 1, -1);
        long offset = REQ_LONG(in, "offset", 1, -1);
        long limit = REQ_LONG(in, "limit", 1, -1);

        out["total_record"] = "0";
     //   res = pgsql_query("SELECT id FROM family_task_suggestion WHERE  status=1 ");
      //  out["total_record"] = pgsql_num_rows(res);

        res = pgsql_query("SELECT sg.*,mf.firstname,to_char(sg.created, 'Day Mon dd, yyyy HH:MI AM') AS formarted_added "
                          " FROM members_family_suggesttask sg "
                          " LEFT JOIN members_family mf ON mf.uid::text = sg.family_uid "
                          " WHERE sg.family_uid::text IN (SELECT uid::text FROM members_family "
                          " WHERE member_id = %lu ) "
                          " AND sg.status IN ( 1,2,3,4,5) "
                          " ORDER BY sg.created DESC LIMIT %lu OFFSET %lu", member_id, limit, offset);

          if (res != NULL && pgsql_num_rows(res) > 0) {
              out["total_record"] = pgsql_num_rows(res);

              for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                  map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                  if (f.empty()) continue;
                  CVars rec;
                  map_to_cvars(f, rec);

                    snprintf(vname, sizeof (vname), "uid_%05d", i);
                    out[vname] = rec["uid"];

                    snprintf(vname, sizeof (vname), "family_uid_%05d", i);
                    out[vname] = rec["family_uid"];

                    snprintf(vname, sizeof (vname), "title_%05d", i);
                    out[vname] = rec["title"];

                    snprintf(vname, sizeof (vname), "description_%05d", i);
                    out[vname] = rec["description"];

                    snprintf(vname, sizeof (vname), "added_%05d", i);
                    out[vname] = rec["formarted_added"];

                    snprintf(vname, sizeof (vname), "status_%05d", i);
                    out[vname] = rec["status"];

                    snprintf(vname, sizeof (vname), "banner_%05d", i);
                    out[vname] = rec["banner"];

                    snprintf(vname, sizeof (vname), "firstname_%05d", i);
                    out[vname] = rec["firstname"];

              }
          }
          ret = PHP_API_OK;
          out["status"] = "OK";

    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchSuggestWaitingList");
    }

 logfmt(logINFO, "WrenchSuggestList()");
 return ret;
}

long  WrenchSuggestList(CVars in, CVars &out){
  logfmt(logINFO, "ENTER CALL long WrenchSuggestList");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    const PGresult *res;
    try{
        long member_id = REQ_LONG(in, "member_id", 1, -1);
        long offset = REQ_LONG(in, "offset", 1, -1);
        long limit = REQ_LONG(in, "limit", 1, -1);

        out["total_record"] = "0";
     //   res = pgsql_query("SELECT id FROM family_task_suggestion WHERE  status=1 ");
      //  out["total_record"] = pgsql_num_rows(res);
//ALTER TABLE members_family_suggesttask ADD remind  timestamp;
        res = pgsql_query(" SELECT * FROM members_family_suggesttask WHERE member_id = %lu AND status IN ( 1,2,3,4,5)   "
                            " ORDER BY created DESC LIMIT %lu OFFSET %lu", member_id, limit, offset);

          if (res != NULL && pgsql_num_rows(res) > 0) {
              out["total_record"] = pgsql_num_rows(res);

              for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                  map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                  if (f.empty()) continue;
                  CVars rec;
                  map_to_cvars(f, rec);

                    snprintf(vname, sizeof (vname), "uid_%05d", i);
                    out[vname] = rec["uid"];

                    snprintf(vname, sizeof (vname), "title_%05d", i);
                    out[vname] = rec["title"];

                    snprintf(vname, sizeof (vname), "description_%05d", i);
                    out[vname] = rec["description"];

                    snprintf(vname, sizeof (vname), "added_%05d", i);
                    out[vname] = rec["created"];

                    snprintf(vname, sizeof (vname), "status_%05d", i);
                    out[vname] = rec["status"];

                    snprintf(vname, sizeof (vname), "banner_%05d", i);
                    out[vname] = rec["banner"];

                    snprintf(vname, sizeof (vname), "remind_%05d", i);
                    out[vname] = rec["remind"];


              }
          }
          ret = PHP_API_OK;
          out["status"] = "OK";

    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchSuggestList");
    }

 logfmt(logINFO, "WrenchSuggestList()");
 return ret;
}

long  WrenchSuggestTaskStatus(CVars in, CVars &out){
    long ret = PHP_API_BAD_PARAM;
    CVars xy;
    CVars xout;
   // const PGresult *res;
    try{
        long member_id = REQ_LONG(in, "member_id", 1, -1);
        REQ_STRING(in, "uid", 3, 150, "(.*)");
        REQ_STRING(in, "suggest_uid", 3, 150, "(.*)");
        long suggest_action = REQ_LONG(in, "suggest_action", 1, -1);

        out["suggested_task_id"] ="0";// we will set if all okay
        const PGresult *res = pgsql_query("SELECT m.*,mf.uid AS family_uid FROM members m "
                                          " LEFT JOIN members_family mf ON mf.family_member_id = m.id "
                                          " WHERE m.id=%lu AND m.uid='%s'", member_id, in["uid"].c_str());
        if (res != NULL && pgsql_num_rows(res) > 0) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
            CVars rec;
            map_to_cvars(f, rec);
            ret = PHP_API_OK;
            out["status"] = "ACCOUNT FOUND";
            //out = rec;
            if (rec["family_uid"] != ""){ // we are sure you are a family now
            // NOW LET US FIND THIS TASK
			 logfmt(logINFO, " CALL long WrenchSuggestTaskStatus- NOW LET US FIND THIS TASK");

          const PGresult *res0 = pgsql_query("SELECT id AS suggest_id,* FROM members_family_suggesttask "
                                            " WHERE member_id = %lu AND uid='%s' AND status IN (1,2)", member_id, in["suggest_uid"].c_str());
                if (res0 != NULL && pgsql_num_rows(res0) > 0) {
                    map<const char*, const char*>f = pgsql_fetch_assoc(res0, 0);
                    CVars rec2;
                    map_to_cvars(f, rec2);

                    if (suggest_action == 555 ){
                          pgsql_exec("UPDATE members_family_suggesttask SET status=0,updated=now() "
                                     " WHERE id=%lu AND uid='%s'", rec2["suggest_id"].Long(),in["suggest_uid"].c_str() );
                        out["status"] = "OK";
                        out["status_msg"] = "family_suggest_deleted";
                        ret = PHP_API_OK;
                    }

                    if (suggest_action == 222 ){
                            pgsql_exec("UPDATE members_family_suggesttask SET remind=now(),updated=now() "
                                       " WHERE id=%lu AND uid='%s'", rec2["suggest_id"].Long(), in["suggest_uid"].c_str() );
                      family_email(WRENCHBOARD_FAMILY_SGGESTTASKS, rec2, rec2);
                       out["status"] = "OK";
                       out["status_msg"] = "family_suggest_reminder_sent";
                      ret = PHP_API_OK;

                      if ( load_db_record(xy, "SELECT m.id AS member_id, m.uid AS member_uid "
                                              " FROM members_family f "
                                              " LEFT JOIN members m ON m.id = f.member_id  "
                                              " WHERE f.family_member_id =  %lu ",rec2["member_id"].Long()) > 0 ){
                                   xy["msg"] = "You have received a suggested task reminder";
                                   xy["msg"].set_valid(true);
                                   plan_notification(xy, xout);
                       }

                    }
                }
            }
        }
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchSuggestTaskStatus");
    }
 logfmt(logINFO, "WrenchSuggestTaskStatus()");
 return ret;
}


long  WrenchSuggestTasks(CVars in, CVars &out){
    long ret = PHP_API_BAD_PARAM;
   // const PGresult *res;
    try{
        long member_id = REQ_LONG(in, "member_id", 1, -1);
        REQ_STRING(in, "uid", 3, 150, "(.*)");
        REQ_STRING(in, "title", 3, 150, "(.*)");
        REQ_STRING(in, "description", 3, 299, "(.*)");
        REQ_STRING(in, "banner", 3, 25, "(.*)");

        out["suggested_task_id"] ="0";// we will set if all okay
        const PGresult *res = pgsql_query("SELECT m.*,mf.uid AS family_uid FROM members m "
                                          " LEFT JOIN members_family mf ON mf.family_member_id = m.id "
                                          " WHERE m.id=%lu AND m.uid='%s'", member_id, in["uid"].c_str());
        if (res != NULL && pgsql_num_rows(res) > 0) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
            CVars rec;
            map_to_cvars(f, rec);
            ret = PHP_API_OK;
            out["status"] = "ACCOUNT FOUND";
            //out = rec;
            if (rec["family_uid"] != ""){ // we are sure you are a family now

            CVars xx;
            xx["member_id"] = member_id;
            xx["member_id"].set_valid(true);
            xx["title"] = in["title"];
            xx["title"].set_valid(true);
            xx["description"] = in["description"];
            xx["description"].set_valid(true);
            xx["family_uid"] = rec["family_uid"];
            xx["family_uid"].set_valid(true);

            xx["banner"] = in["banner"];
            xx["banner"].set_valid(true);

            out["suggested_task_id"] = insert_db_record(DBS_VALID, "members_family_suggesttask", "members_family_suggesttask_id_seq", xx);
            if(out["suggested_task_id"].Long()  > 0  ){
             load_db_record( out, "SELECT id AS suggest_id,* FROM members_family_suggesttask WHERE id = %lu ", out["suggested_task_id"].Long());
              family_email(WRENCHBOARD_FAMILY_SGGESTTASKS, out, out); //
            }
            ret = PHP_API_OK;
            out["status"] = "OK";
            }
        }
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchSuggestTasks");
    }

 logfmt(logINFO, "WrenchSuggestTasks()");
 return ret;
}

long  WrenchSampleTasks(CVars in, CVars &out){
  logfmt(logINFO, "ENTER CALL long WrenchSampleTasks");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    const PGresult *res;
    try{
        long member_id = REQ_LONG(in, "member_id", 1, -1);
        long offset = REQ_LONG(in, "offset", 1, -1);
        long limit = REQ_LONG(in, "limit", 1, -1);

        out["total_record"] = "0";
     //   res = pgsql_query("SELECT id FROM family_task_suggestion WHERE  status=1 ");
      //  out["total_record"] = pgsql_num_rows(res);

        res = pgsql_query(" SELECT * FROM family_task_suggestion WHERE status = 1  "
                            " ORDER BY title DESC LIMIT %lu OFFSET %lu", limit, offset);

          if (res != NULL && pgsql_num_rows(res) > 0) {
              out["total_record"] = pgsql_num_rows(res);

              for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                  map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                  if (f.empty()) continue;
                  CVars rec;
                  map_to_cvars(f, rec);

                    snprintf(vname, sizeof (vname), "uid_%05d", i);
                    out[vname] = rec["uid"];

                    snprintf(vname, sizeof (vname), "title_%05d", i);
                    out[vname] = rec["title"];

                    snprintf(vname, sizeof (vname), "description_%05d", i);
                    out[vname] = rec["description"];

                    snprintf(vname, sizeof (vname), "added_%05d", i);
                    out[vname] = rec["added"];

                    snprintf(vname, sizeof (vname), "age_%05d", i);
                    out[vname] = rec["age"];

                    snprintf(vname, sizeof (vname), "banner_%05d", i);
                    out[vname] = rec["banner"];

              }
          }
          ret = PHP_API_OK;
          out["status"] = "OK";

    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchSampleTasks");
    }

 logfmt(logINFO, "WrenchSampleTasks()");
 return ret;
}

long WrenchFamilyTransfer(CVars in, CVars &out){
    logfmt(logINFO, "ENTER CALL long WrenchFamilyTransfer");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    long family_member_id = 0;
    const PGresult *res0;
    int err_count = 0;

    try {
    /*
    member_id' => int 1
      'sessionid' => string '64C3E325C554381B055233298A267198A1F19251E2DBD04634B3E6A58847DC0B' (length=64)
      'uid' => string '3119b744-42ad-4834-bb83-b737588754ca' (length=36)
      'family_uid' => string '1f385837-b5e6-420e-a17a-488c4b8ef015' (length=36)
      'wallet_uid' => string 'aa6e6488-2e71-4f83-b265-27c3c4339f73' (length=36)
      'origing_wallet_uid' => string 'cc0f8743-3f18-4214-ba4b-781e5dda9cb8' (length=36)
      'currency' => string 'NAIRA' (length=5)
      'amount' => int 100500
      'family_transfer_mode' => int 100
    */
   // }
        long member_id = REQ_LONG(in, "member_id", 1, -1);
        long amount = REQ_LONG(in, "amount", 1, -1);
        REQ_STRING(in, "family_uid", 2, 50, "(.*)");
        REQ_STRING(in, "uid", 2, 50, "(.*)");
        REQ_STRING(in, "wallet_uid", 2, 50, "(.*)");
        REQ_STRING(in, "origing_wallet_uid", 2, 50, "(.*)");
        REQ_STRING(in, "sessionid", 2, 149, "(.*)");
        REQ_STRING(in, "currency", 2, 20, "(.*)");
        REQ_STRING(in, "description", 2, 100, "(.*)");
    	logfmt(logINFO, "WrenchFamilyWallet() Verify Session ");
    	CVars rec0;
    	if ( VerifySession(in, out) != PHP_API_OK ){
    	   return ret;
    	}

        res0 = pgsql_query("SELECT family_member_id FROM members_family WHERE member_id = %lu AND uid='%s' ", in["member_id"].Long(), in["family_uid"].c_str());
        if (res0 != NULL && pgsql_num_rows(res0) > 0) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res0, 0);
            map_to_cvars(f, rec0);
            family_member_id = rec0["family_member_id"].Long();
        }
        else{
           out["status"] = "Family not found";
           return ret;
        }

        out["total_record"] = "0";
        const PGresult *res;
        res = pgsql_query("SELECT w.amount AS current_balance, w.currency, w.uid AS recipient_wallet_uid "
                           "FROM members_wallet w LEFT JOIN currency c ON c.code=w.currency "
                            "WHERE w.member_id = %lu AND w.uid='%s' ORDER BY c.lorder DESC", rec0["family_member_id"].Long(), in["wallet_uid"].c_str());

        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["total_record"] = pgsql_num_rows(res);
                map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
                CVars rec;
                map_to_cvars(f, rec);
                out =  rec;
                // lets get the parent wallet too
                if( load_db_record(out,"SELECT w.amount AS origing_current_balance,w.uid AS origing_wallet_uid,"
                                       " w.transfer_limit AS origing_transfer_limit, w.currency as origing_currency "
                                       " FROM members_wallet w "
                                       " WHERE w.member_id = %lu  AND w.currency='%s' AND w.uid='%s'", in["member_id"].Long(), out["currency"].c_str(), in["origing_wallet_uid"].c_str()) >0 ){


                            if (in["amount"].Long() > out["origing_transfer_limit"].Long() ){
                            err_count++;
                            out["error_limit"] = "amount_greater_than_limit";
                            }

                            if (in["amount"].Long() <= 0  ){
                              err_count++;
                              out["error_balance"] = "amount_inavlid";
                            }

                            if (in["amount"].Long() > out["origing_current_balance"].Long() ){
                              err_count++;
                              out["error_balance"] = "amount_greater_than_balance";
                            }

                            if (err_count> 0){
                                    out["status"] = "Send Error";
                                    return ret;
                            }
                           CVars inx;
                           inx["member_id"] =  in["member_id"];  inx["member_id"].set_valid( true );
                           inx["recipient"] =  rec0["family_member_id"];  inx["recipient"].set_valid( true );
                           inx["uid"] = in["uid"];  inx["uid"].set_valid( true );
                           inx["currency"]  = in["currency"];  inx["currency"].set_valid( true );
                           inx["origing_wallet"] = in["origing_wallet_uid"];  inx["origing_wallet"].set_valid( true );
                           inx["target_wallet"] = out["recipient_wallet_uid"];  inx["target_wallet"].set_valid( true );
                           inx["amount"]  = in["amount"];  inx["amount"].set_valid( true );
                           inx["description"] =  in["description"];  inx["description"].set_valid( true );

                           long family_transfer_id = insert_db_record(DBS_VALID, "family_transfer", "family_transfer_id_seq", inx);

                           if ( family_transfer_id >  0 ){
                           CVars trx;
                            if (   load_db_record(trx, "SELECT * FROM family_transfer WHERE id =%lu",family_transfer_id) >  0  ){
                            trx["transfer_id"] = family_transfer_id;  trx["transfer_id"].set_valid( true );
                                   return  WrenchFamilyPayment( trx, out );
                            }
                            else{
                                out["status"] = "System Error 02";
                                return ret;
                            }

                           }
                           else
                           {
                                out["status"] = "System Error 01";
                                return ret;
                           }

/*

CREATE TABLE family_transfer (
		id SERIAL,
		uid uuid DEFAULT  uuid_generate_v4(),
		member_id INT REFERENCES members(id) NOT NULL,
		recipient INT REFERENCES members(id) NOT NULL,
		origing_wallet VARCHAR(150) NOT NULL,
		target_wallet VARCHAR(150) NOT NULL,
		amount INT Default 0,
		currency VARCHAR(5) REFERENCES currency(code),
		description VARCHAR(150),
		status INT DEFAULT 1,
		flags  INT DEFAULT 0,
		added timestamp without time zone DEFAULT now(),
		updated timestamp without time zone DEFAULT now()
	);
 ALTER TABLE ONLY family_transfer
    ADD CONSTRAINT family_transfer_id_key UNIQUE (id);
    */

                    }
                    else{
                        out["status"] = "Originating wallet not found";
                    }
        }
     } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchFamilyTransfer(CVars in, CVars &out)");
    }

   logfmt(logINFO, "EXIT CALL long WrenchFamilyTransfer");
  return 0;
}

long WrenchFamilyTransferHx(CVars in, CVars &out){

  logfmt(logINFO, "ENTER CALL long WrenchFamilyTransferHx");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    const PGresult *res;
    try{
        long member_id = REQ_LONG(in, "member_id", 1, -1);
        long offset = REQ_LONG(in, "offset", 1, -1);
        long limit = REQ_LONG(in, "limit", 1, -1);

        out["total_record"] = "0";
/*
wrenchboard=> \d family_transfer
                                          Table "public.family_transfer"
     Column     |            Type             | Collation | Nullable |                   Default
----------------+-----------------------------+-----------+----------+---------------------------------------------
 id             | integer                     |           | not null | nextval('family_transfer_id_seq'::regclass)
 uid            | uuid                        |           |          | uuid_generate_v4()
 member_id      | integer                     |           | not null |
 recipient      | integer                     |           | not null |
 origing_wallet | character varying(150)      |           | not null |
 target_wallet  | character varying(150)      |           | not null |
 amount         | integer                     |           |          | 0
 currency       | character varying(5)        |           |          |
 description    | character varying(150)      |           |          |
 status         | integer                     |           |          | 1
 flags          | integer                     |           |          | 0
 added          | timestamp without time zone |           |          | now()
 updated        | timestamp without time zone |           |          | now()
 pay_confirm    | character varying(15)       |           |          |
 credit_confirm | character varying(15)       |           |          |
Indexes:

*/

        res = pgsql_query(" SELECT f.*, m.firstname, m.lastname FROM family_transfer f "
                          " LEFT JOIN members m ON m.id = f.recipient "
                          " WHERE member_id = %lu AND f.status IN ( 1 ) "
                          " ORDER BY added DESC LIMIT %lu OFFSET %lu", member_id, limit, offset);

          if (res != NULL && pgsql_num_rows(res) > 0) {
              out["total_record"] = pgsql_num_rows(res);

              for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                  map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                  if (f.empty()) continue;
                  CVars rec;
                  map_to_cvars(f, rec);



                    snprintf(vname, sizeof (vname), "uid_%05d", i);
                    out[vname] = rec["uid"];

                    snprintf(vname, sizeof (vname), "amount_%05d", i);
                    out[vname] = rec["amount"];

                    snprintf(vname, sizeof (vname), "currency_%05d", i);
                    out[vname] = rec["currency"];

                    snprintf(vname, sizeof (vname), "recipient_%05d", i);
                    out[vname] = rec["recipient"];

                    snprintf(vname, sizeof (vname), "rec_firstname_%05d", i);
                    out[vname] = rec["firstname"];

                    snprintf(vname, sizeof (vname), "rec_lastname_%05d", i);
                    out[vname] = rec["lastname"];

                    snprintf(vname, sizeof (vname), "description_%05d", i);
                    out[vname] = rec["description"];

                    snprintf(vname, sizeof (vname), "flags_%05d", i);
                    out[vname] = rec["flags"];

                    snprintf(vname, sizeof (vname), "status_%05d", i);
                    out[vname] = rec["status"];

                    snprintf(vname, sizeof (vname), "confirmation_%05d", i);
                    out[vname] = rec["credit_confirm"];

                    snprintf(vname, sizeof (vname), "added_%05d", i);
                    out[vname] = rec["added"];


              }
          }
          ret = PHP_API_OK;
          out["status"] = "OK";

    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchFamilyTransferHx");
    }

 logfmt(logINFO, "WrenchFamilyTransferHx()");
 return ret;




}


long WrenchFamilyTransferStart(CVars in, CVars &out){
    logfmt(logINFO, "ENTER CALL long WrenchFamilyWallet");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    long family_member_id = 0;
    const PGresult *res0;

    try {
        long member_id = REQ_LONG(in, "member_id", 1, -1);
        REQ_STRING(in, "family_uid", 2, 50, "(.*)");
        REQ_STRING(in, "uid", 2, 50, "(.*)");
         REQ_STRING(in, "wallet_uid", 2, 50, "(.*)");
        REQ_STRING(in, "sessionid", 2, 149, "(.*)");
    	logfmt(logINFO, "WrenchFamilyWallet() Verify Session ");
    	CVars rec0;
    	if ( VerifySession(in, out) != PHP_API_OK ){
    	   return 0;
    	}

        res0 = pgsql_query("SELECT family_member_id FROM members_family WHERE member_id = %lu AND uid='%s' ", in["member_id"].Long(), in["family_uid"].c_str());
        if (res0 != NULL && pgsql_num_rows(res0) > 0) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res0, 0);
            map_to_cvars(f, rec0);
            family_member_id = rec0["family_member_id"].Long();
        }
        else{
           return 0;
        }

        out["total_record"] = "0";
        const PGresult *res;
        res = pgsql_query("SELECT w.amount AS current_balance, w.currency, w.uid AS recipient_wallet_uid "
                           "FROM members_wallet w LEFT JOIN currency c ON c.code=w.currency "
                            "WHERE w.member_id = %lu AND w.uid='%s' ORDER BY c.lorder DESC", rec0["family_member_id"].Long(), in["wallet_uid"].c_str());

        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["total_record"] = pgsql_num_rows(res);

                map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
                CVars rec;
                map_to_cvars(f, rec);
                out =  rec;
                // lets get the parent wallet too
                if( load_db_record(out,"SELECT w.amount AS origing_current_balance,w.uid AS origing_wallet_uid,"
                                       " w.transfer_limit AS origing_transfer_limit, w.currency as origing_currency "
                                       " FROM members_wallet w "
                                       " WHERE w.member_id = %lu  AND w.currency='%s'", in["member_id"].Long(), out["currency"].c_str()) ){
                    ret = PHP_API_OK;
                        out["status"] = "OK";
                        out["exchange_rate"] ="1";
                    }
                    else{
                        out["status"] = "Originating wallet not found";
                    }
        }
        ret = PHP_API_OK;
        out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchFamilyTransferStart(CVars in, CVars &out)");
    }

   logfmt(logINFO, "EXIT CALL long WrenchFamilyTransferStart");
  return 0;
}

long WrenchFamilyWallet(CVars in, CVars &out){
    logfmt(logINFO, "ENTER CALL long WrenchFamilyWallet");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    long family_member_id = 0;
    const PGresult *res0;

    try {
        long member_id = REQ_LONG(in, "member_id", 1, -1);
        REQ_STRING(in, "family_uid", 2, 50, "(.*)");
        REQ_STRING(in, "uid", 2, 50, "(.*)");
        REQ_STRING(in, "sessionid", 2, 149, "(.*)");
    	logfmt(logINFO, "WrenchFamilyWallet() Verify Session ");
    	CVars rec0;
    	if ( VerifySession(in, out) != PHP_API_OK ){
    	   return 0;
    	}

        res0 = pgsql_query("SELECT family_member_id FROM members_family WHERE member_id = %lu AND uid='%s' ", in["member_id"].Long(), in["family_uid"].c_str());
        if (res0 != NULL && pgsql_num_rows(res0) > 0) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res0, 0);
            map_to_cvars(f, rec0);
            family_member_id = rec0["family_member_id"].Long();

                CVars vw;
                if( load_db_record(vw, "SELECT c.code AS currency from members m LEFT JOIN currency c ON c.country = m.country WHERE m.id=%lu AND m.country IS NOT NULL",in["member_id"].Long())> 0 ){
                     logfmt(logINFO, "********~~~~~~~~ WrenchFamilyWallet() ------ CheckWallet(family_member_id) = %lu",family_member_id);
                   // vw["currency"] = "NAIRA";  // this might become a variable based on the country
                    //vw["currency"].set_valid( true );
                     long wallet_id = CheckWallet(family_member_id,vw); // making sure we have a wallet
                }
        }
        else{
        out["error_msg"] ="member_family_wallet_not_found";
           return 0;
        }



        out["total_record"] = "0";
        const PGresult *res;
        res = pgsql_query("SELECT w.amount,c.*,w.amount AS current_balance,c.country,w.transfer_limit,w.uid AS wallet_uid "
                           "FROM members_wallet w LEFT JOIN currency c ON c.code=w.currency "
                            "WHERE w.member_id = %lu ORDER BY c.lorder DESC", rec0["family_member_id"].Long());

        if (res != NULL && pgsql_num_rows(res) > 0) {
            out["total_record"] = pgsql_num_rows(res);

            for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                if (f.empty()) continue;
                CVars rec;
                map_to_cvars(f, rec);

                snprintf(vname, sizeof (vname), "amount_%05d", i);
                out[vname] = rec["amount"];
                snprintf(vname, sizeof (vname), "currency_%05d", i);
                out[vname] = rec["currency"];

                // amount  | id | code  | description | symbol |  action_type  | lorder | current_balance
                snprintf(vname, sizeof (vname), "description_%05d", i);
                out[vname] = rec["description"];

                snprintf(vname, sizeof (vname), "symbol_%05d", i);
                out[vname] = rec["symbol"];

                snprintf(vname, sizeof (vname), "action_type_%05d", i);
                out[vname] = rec["action_type"];

                snprintf(vname, sizeof (vname), "code_%05d", i);
                out[vname] = rec["code"];

                snprintf(vname, sizeof (vname), "country_%05d", i);
                out[vname] = rec["country"];

                snprintf(vname, sizeof (vname), "transfer_limit_%05d", i);
                out[vname] = rec["transfer_limit"];

                snprintf(vname, sizeof (vname), "wallet_uid_%05d", i);
                out[vname] = rec["wallet_uid"];


            }
        }
        ret = PHP_API_OK;
        out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchFamilyWallet(CVars in, CVars &out)");
    }

   logfmt(logINFO, "EXIT CALL long WrenchFamilyWallet");
  return 0;
}

//,to_char(last_login, 'Day Mon dd, yyyy HH:MI AM')
long  WrenchFamilyList(CVars in, CVars &out){
    logfmt(logINFO, "ENTER CALL long WrenchFamilyList");
    char vname[30];
    long ret = PHP_API_BAD_PARAM;
    const PGresult *res;
    try{
        long member_id = REQ_LONG(in, "member_id", 1, -1);
        long offset = REQ_LONG(in, "offset", 1, -1);
        long limit = REQ_LONG(in, "limit", 1, -1);

        out["total_record"] = "0";
        res = pgsql_query("SELECT id FROM members_family WHERE member_id = %lu AND status=1 ", in["member_id"].Long());
        out["total_record"] = pgsql_num_rows(res);

        res = pgsql_query(" SELECT *,to_char(last_login, 'Day Mon dd, yyyy HH:MI AM') AS last_login_formatted  FROM members_family WHERE member_id = %lu AND status=1 "
                            " ORDER BY id DESC LIMIT %lu OFFSET %lu", in["member_id"].Long(), limit, offset);

          if (res != NULL && pgsql_num_rows(res) > 0) {
              out["total_record"] = pgsql_num_rows(res);

              for (int i = 0, n = pgsql_num_rows(res); i < n; i++) {
                  map<const char*, const char*>f = pgsql_fetch_assoc(res, i);
                  if (f.empty()) continue;
                  CVars rec;
                  map_to_cvars(f, rec);

                 snprintf(vname, sizeof (vname), "uid_%05d", i);
                 out[vname] = rec["uid"];

                  snprintf(vname, sizeof (vname), "firstname_%05d", i);
                  out[vname] = rec["firstname"];

                  snprintf(vname, sizeof (vname), "lastname_%05d", i);
                  out[vname] = rec["lastname"];

                  snprintf(vname, sizeof (vname), "added_%05d", i);
                  out[vname] = rec["added"];

                  snprintf(vname, sizeof (vname), "age_%05d", i);
                  out[vname] = rec["age"];

                 snprintf(vname, sizeof (vname), "last_login_%05d", i);
                 out[vname] = rec["last_login_formatted"];

                 snprintf(vname, sizeof (vname), "task_count_%05d", i);
                 out[vname] = rec["task_count"];

                snprintf(vname, sizeof (vname), "username_%05d", i);
                out[vname] = rec["username"];

                snprintf(vname, sizeof (vname), "year_%05d", i);
                out[vname] = rec["year"];

                snprintf(vname, sizeof (vname), "month_%05d", i);
                out[vname] = rec["month"];

                snprintf(vname, sizeof (vname), "enable_traking_%05d", i);
                out[vname] = rec["enable_traking"];

              }
          }
          ret = PHP_API_OK;
          out["status"] = "OK";

    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchFamilyList");
    }

 logfmt(logINFO, "WrenchFamilyList()");
return ret;
}

long  WrenchFamilyInitializeAccount(CVars in, CVars &out);
long  WrenchFamilyAdd(CVars in, CVars &out){
 logfmt(logINFO, "WrenchFamilyAdd()");
  long family_id = 0;

  try {
		REQ_LONG(in, "member_id", 1, -1);
		//REQ_LONG(in, "age", 1, -1);
        REQ_LONG(in, "year", 1, -1);
        REQ_LONG(in, "month", 1, -1);
		REQ_STRING(in, "firstname", 2, 34, "(.*)");
		REQ_STRING(in, "lastname", 2, 34, "(.*)");
        CVars x;
        x["member_id"] = in["member_id"];
        x["member_id"].set_valid(true);
        x["age"] = "0";
        x["age"].set_valid(true);
        x["firstname"] = in["firstname"];
        x["firstname"].set_valid(true);
        x["lastname"] = in["lastname"];
        x["lastname"].set_valid(true);
        x["status"] = "1";
        x["status"].set_valid(true);

        x["year"] = in["year"];
        x["year"].set_valid(true);

        x["month"] = in["month"];
        x["month"].set_valid(true);

        family_id = insert_db_record(DBS_VALID, "members_family", "members_family_id_seq", x);
        if (family_id > 0) {
         load_db_record(out, "SELECT id AS family_id, * FROM members_family WHERE id =%lu",family_id);
         WrenchFamilyInitializeAccount(out,out);
          // send notice here

		}
		out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchFamilyAdd(CVars in, CVars &out)");
    }
  logfmt(logINFO, "WrenchFamilyAdd()");
return family_id;
}

long  WrenchFamilyUpdate(CVars in, CVars &out){
 long ret = PHP_API_BAD_PARAM;
  logfmt(logINFO, "WrenchFamilyUpdate()");
  long family_id = 0;
  try {
		long member_id = REQ_LONG(in, "member_id", 1, -1);
		REQ_STRING(in, "firstname", 2, 34, "(.*)");
		REQ_STRING(in, "lastname", 2, 34, "(.*)");
		REQ_STRING(in, "family_uid", 2, 50, "(.*)");
        REQ_LONG(in, "year", 1, -1);
        REQ_LONG(in, "month", 1, -1);
        REQ_LONG(in, "enable_traking", 1, -1);

        CVars x;
        x["firstname"] = in["firstname"];
        x["firstname"].set_valid(true);
        x["lastname"] = in["lastname"];
        x["lastname"].set_valid(true);

        x["year"] = in["year"];
        x["year"].set_valid(true);
        x["month"] = in["month"];
        x["month"].set_valid(true);

        x["enable_traking"] = in["enable_traking"];
        x["enable_traking"].set_valid(true);

        const PGresult *res = pgsql_query(" SELECT id AS family_id FROM members_family "
                                          " WHERE member_id=%lu AND uid='%s' ", member_id,in["family_uid"].c_str());
        if (res != NULL && pgsql_num_rows(res) > 0) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
            CVars rec;
            map_to_cvars(f, rec);
            update_db_record(DBS_VALID, "members_family", x, rec["family_id"].Long());
            ret = PHP_API_OK;
        }
		out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchFamilyUpdate(CVars in, CVars &out)");
    }
 logfmt(logINFO, "WrenchFamilyUpdate()");
return ret;
}


long  WrenchFamilyManage(CVars in, CVars &out){
/*
wrenchboard=> select * from members_family;
 id | member_id | firstname | lastname | age | active | status | added | updated
----+-----------+-----------+----------+-----+--------+--------+-------+---------
(0 rows)
*/
 long ret = PHP_API_BAD_PARAM;
  logfmt(logINFO, "WrenchFamilyManage()");
  long family_id = 0;
  try {
		long member_id = REQ_LONG(in, "member_id", 1, -1);
		REQ_STRING(in, "uid", 2, 45, "(.*)");
		REQ_STRING(in, "family_uid", 2, 45, "(.*)");

        const PGresult *res = pgsql_query(" SELECT id AS family_id,* FROM members_family "
                                          " WHERE member_id=%lu AND uid='%s' ", member_id,in["family_uid"].c_str());
        if (res != NULL && pgsql_num_rows(res) > 0) {
            map<const char*, const char*>f = pgsql_fetch_assoc(res, 0);
            CVars rec;
            map_to_cvars(f, rec);
            if( rec["username"]=="" || rec["pin"]==""){
              logfmt(logINFO, "WrenchFamilyManage()- NEED TI INITIALIZE  USERNAME PIN");
              WrenchFamilyInitializeAccount(rec,out);
            }
            if( rec["family_member_id"]==""){
             WrenchBoardFamilyAccMemberID(in, out);
            }

            out = rec;
            ret = PHP_API_OK;
        }
		out["status"] = "OK";
    } catch (bad_parameter) {
        logfmt(logINFO, "ERROR CALL long WrenchFamilyUpdate(CVars in, CVars &out)");
    }

  logfmt(logINFO, "/WrenchFamilyManage()");
return ret;
}

/* WARNING: Unsafe function without buffer length check! */
void GeneratePIN(int length, char *buffer) {
    if (length < 2) {
      sprintf(buffer, "%d", rand() % 10); // if the PIN length is less than 2 - make a single digit
      return;
    }
    // leading number must not be 0
    long long randomNumber = (rand() % 9) + 1;
    const int n = length - 1;
    for (int i = 0; i<n; i++) {
        randomNumber *= 10;
        randomNumber += rand() % 10;
    }
    sprintf(buffer, "%0*ld", length, randomNumber);
}


long  WrenchFamilyInitializeAccount(CVars in, CVars &out){
    const PGresult *res;
    char username[7] = "";
    logfmt(logINFO, "WrenchFamilyInitializeAccount()");
    try {

            SetFamilyUsername(in["family_id"].Long(), username, 6);
             } catch (bad_parameter) {
                logfmt(logINFO, "ERROR CALL void SetFamilyUsername(CVars in, CVars &out)");
        }
/*
    int r1;
    //srand(time(NULL));
    r1 = 1000+(rand()%9000);
    pgsql_exec("UPDATE members_family SET pin='%s' WHERE id=%lu", r1, in["family_id"].Long() );
  */
    char pin[5]; // 4 digits + \0  
    bzero(pin, sizeof (pin));
    GeneratePIN(4, pin);

    pgsql_exec("UPDATE members_family SET pin='%s' WHERE id=%lu", pin, in["family_id"].Long() );

    load_db_record(out, "SELECT * FROM members_family WHERE id = %lu", in["family_id"].Long());

    return 0;
}



/*

#define WRENCHBOARD_FAMILY_LIST           22010
#define WRENCHBOARD_FAMILY_ADD            22015
#define WRENCHBOARD_FAMILY_UPDATE         22020
#define WRENCHBOARD_FAMILY_MANAGE         22025
*/
