/*
 * This file is distributed as part of MaxScale.  It 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,
 * version 2.
 *
 * 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., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Copyright MariaDB Corporation Ab 2014
 */

#include "maxadmin_operations.h"

int
connectMaxScale(char *hostname, char *port)
{
    struct sockaddr_in  addr;
    int         so;
    int         keepalive = 1;

    if ((so = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        fprintf(stderr, "Unable to create socket: %s\n",
                strerror(errno));
        return -1;
    }
    memset(&addr, 0, sizeof addr);
    addr.sin_family = AF_INET;
    setipaddress(&addr.sin_addr, hostname);
    addr.sin_port = htons(atoi(port));
    if (connect(so, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        fprintf(stderr, "Unable to connect to MaxScale at %s, %s: %s\n",
                hostname, port, strerror(errno));
        close(so);
        return -1;
    }
    if (setsockopt(so, SOL_SOCKET,
                   SO_KEEPALIVE, &keepalive , sizeof(keepalive )))
    {
        perror("setsockopt");
    }

    return so;
}


int
setipaddress(struct in_addr *a, char *p)
{
#ifdef __USE_POSIX
    struct addrinfo *ai = NULL, hint;
    int    rc;
    struct sockaddr_in * res_addr;
    memset(&hint, 0, sizeof (hint));

    hint.ai_socktype = SOCK_STREAM;
    hint.ai_flags = AI_CANONNAME;
    hint.ai_family = AF_INET;

    if ((rc = getaddrinfo(p, NULL, &hint, &ai)) != 0)
    {
        return 0;
    }

    /* take the first one */
    if (ai != NULL)
    {
        res_addr = (struct sockaddr_in *)(ai->ai_addr);
        memcpy(a, &res_addr->sin_addr, sizeof(struct in_addr));

        freeaddrinfo(ai);

        return 1;
    }
#else
    struct hostent *h;

    spinlock_acquire(&tmplock);
    h = gethostbyname(p);
    spinlock_release(&tmplock);

    if (h == NULL)
    {
        if ((a->s_addr = inet_addr(p)) == -1)
        {
            return 0;
        }
    }
    else
    {
        /* take the first one */
        memcpy(a, h->h_addr, h->h_length);

        return 1;
    }
#endif
    return 0;
}

int
authMaxScale(int so, char *user, char *password)
{
    char    buf[20];

    if (read(so, buf, 4) != 4)
    {
        return 0;
    }
    write(so, user, strlen(user));
    if (read(so, buf, 8) != 8)
    {
        return 0;
    }
    write(so, password, strlen(password));
    if (read(so, buf, 6) != 6)
    {
        return 0;
    }

    return strncmp(buf, "FAILED", 6);
}

int
sendCommand(int so, char *cmd, char *buf)
{
    char    buf1[80];
    int i, j, newline = 1;
    int k = 0;

    if (write(so, cmd, strlen(cmd)) == -1)
    {
        return 0;
    }
    while (1)
    {
        if ((i = read(so, buf1, 80)) <= 0)
        {
            return 0;
        }
        for (j = 0; j < i; j++)
        {
            if (newline == 1 && buf1[j] == 'O')
            {
                newline = 2;
            }
            else if (newline == 2 && buf1[j] == 'K' && j == i - 1)
            {
                return 1;
            }
            else if (newline == 2)
            {
                buf[k] = 'O';
                k++;
                buf[k] = buf1[j];
                k++;
                newline = 0;
            }
            else if (buf1[j] == '\n' || buf1[j] == '\r')
            {
                buf[k] = buf1[j];
                k++;
                newline = 1;
            }
            else
            {
                buf[k] = buf1[j];
                k++;
                newline = 0;
            }
        }
    }
    return 1;
}

int
get_maxadmin_param_tcp(char * hostname, char *user, char *password, char * cmd, char *param, char *result)
{

    char        buf[10240];
    char        *port = (char *) "6603";
    int         so;

    if ((so = connectMaxScale(hostname, port)) == -1)
    {
        return 1;
    }
    if (!authMaxScale(so, user, password))
    {
        fprintf(stderr, "Failed to connect to MaxScale. "
                "Incorrect username or password.\n");
        close(so);
        return 1;
    }

    sendCommand(so, cmd, buf);

    //printf("%s\n", buf);

    char * x = strstr(buf, param);
    if (x == NULL )
    {
        return 1;
    }
    //char f_field[100];
    int param_len = strlen(param);
    int cnt = 0;
    while (x[cnt + param_len]  != '\n')
    {
        result[cnt] = x[cnt + param_len];
        cnt++;
    }
    result[cnt] = '\0';
    //sprintf(f_field, "%s %%s", param);
    //sscanf(x, f_field, result);
    close(so);
    return 0;
}

int
execute_maxadmin_command_tcp(char * hostname, char *user, char *password, char * cmd)
{

    char        buf[10240];
    char        *port = (char *) "6603";
    int         so;

    if ((so = connectMaxScale(hostname, port)) == -1)
    {
        return 1;
    }
    if (!authMaxScale(so, user, password))
    {
        fprintf(stderr, "Failed to connect to MaxScale. "
                "Incorrect username or password.\n");
        close(so);
        return 1;
    }

    sendCommand(so, cmd, buf);

    close(so);
    return 0;
}

int
execute_maxadmin_command_print_tcp(char * hostname, char *user, char *password, char * cmd)
{

    char        buf[10240];
    char        *port = (char *) "6603";
    int         so;

    if ((so = connectMaxScale(hostname, port)) == -1)
    {
        return 1;
    }
    if (!authMaxScale(so, user, password))
    {
        fprintf(stderr, "Failed to connect to MaxScale. "
                "Incorrect username or password.\n");
        close(so);
        return 1;
    }

    sendCommand(so, cmd, buf);
    printf("%s\n", buf);
    close(so);
    return 0;
}
