#include "net_address.hpp"
#include "logger.hpp"
#include <arpa/inet.h>
#include <cassert>
#include <cctype>
#include <cstring>
#include <netinet/in.h>
#include <sstream>


namespace tinyrpc {

    NetAddress::NetAddress(const std::string ip, uint16_t port) : m_ip(ip), m_port(port){
        m_addr_in.sin_family = AF_INET;
        inet_pton(AF_INET, ip.c_str(), &m_addr_in.sin_addr.s_addr);
        m_addr_in.sin_port = htons(port);
        // logger() << "NetAddress created:" << toString();
    }

    NetAddress::NetAddress(uint16_t port) : m_ip("0.0.0.0"), m_port(port){
        m_addr_in.sin_family = AF_INET;
        m_addr_in.sin_addr.s_addr = INADDR_ANY;
        m_addr_in.sin_port = htons(port);
        // logger() << "NetAddress created:" << toString();
    }

    NetAddress::NetAddress(const sockaddr_in* addr) {
        assert(addr);
        memcpy(&m_addr_in, addr, sizeof(sockaddr_in));
        char buf[16]{};
        m_ip = inet_ntop(AF_INET, &addr->sin_addr.s_addr, buf, sizeof(buf));
        m_port = ntohs(addr->sin_port);
        // logger() << "NetAddress created from sockaddr_in:" << toString();
    }

    NetAddress::~NetAddress(){

    }

    std::string NetAddress::toString() const{
        std::stringstream ss;
        ss << m_ip << ":" << m_port;
        return ss.str();
    }

    bool NetAddress::checkIpString(const std::string& ip) {
        // 192.168.1.1
        int num_stat = 0; // 0-3
        int dot_stat = 0;  // 0-3

        for(char ch : ip) {
            if(std::isdigit(ch)) {
                if(dot_stat < 0 || dot_stat > 3) {
                    return false;
                }
                num_stat += 1;
                if(num_stat > 3) return false;
            } else if(ch == '.'){
                if(num_stat < 1 || num_stat > 3) {
                    return false;
                }
                dot_stat += 1;
                num_stat = 0;
                if(dot_stat > 3) return false;
            } else {
                return false;
            }
            
        }
        return true;
    }
}