/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */

/*
 * ----------------------------------------------------------------------------------
 * The code in this file is copied (with a slight modifications) from:
 *     lwIPDHCPServer.h - DHCP server
 * ----------------------------------------------------------------------------------
 * Copyright (c) 2016 Espressif. All rights reserved.
 * Copyright (c) 2020 esp8266 arduino. All rights reserved.
 *
 * This file is part of the esp8266 core for Arduino environment.
 *
 * This library is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free Software
 * Foundation; either version 2.1 of the License, or (at your option) any later
 * version.
 *
 * This library 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along
 * with this library; if not, write to the Free Software Foundation, Inc., 51
 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 *
 * ----------------------------------------------------------------------------------
 * Original sources (no license provided)
 *     ESP8266_NONOS_SDK/third_party/lwip/app/dhcpserver.c
 *     ESP8266_NONOS_SDK/third_party/include/lwip/app/dhcpserver.h
 * ----------------------------------------------------------------------------------
 */


#ifndef ECXX_PLATFORM_NODEMCU_LWIP_DHCP_SERVER_H
#define ECXX_PLATFORM_NODEMCU_LWIP_DHCP_SERVER_H


#include <lwip/init.h>


namespace eCxx {

namespace NodeMCU {


class DHCPServer {
    public:
        DHCPServer(netif* netif);
        ~DHCPServer();

        void setDns(int num, const ipv4_addr_t* dns);

        bool begin(ip_info* info);
        void end();
        bool isRunning();

        void init_dhcps_lease(uint32_t ip);
        bool set_dhcps_lease(dhcps_lease* please);
        bool get_dhcps_lease(dhcps_lease* please);
        bool set_dhcps_offer_option(uint8_t level, void* optarg);
        bool set_dhcps_lease_time(uint32_t minute);
        bool reset_dhcps_lease_time();
        uint32_t get_dhcps_lease_time();
        bool add_dhcps_lease(uint8_t* macaddr);

        void dhcps_set_dns(int num, const ipv4_addr_t* dns);

    protected:
        struct list_node {
            void*      pnode;
            list_node* pnext;
        };

    protected:
        void node_insert_to_list(list_node** phead, list_node* pinsert);
        void node_remove_from_list(list_node** phead, list_node* pdelete);
        uint8_t* add_msg_type(uint8_t* optptr, uint8_t type);
        uint8_t* add_offer_options(uint8_t* optptr);
        uint8_t* add_end(uint8_t* optptr);
        void create_msg(struct dhcps_msg* m);
        void send_offer(struct dhcps_msg* m);
        void send_nak(struct dhcps_msg* m);
        void send_ack(struct dhcps_msg* m);
        uint8_t parse_options(uint8_t* optptr, int16_t len);
        int16_t parse_msg(struct dhcps_msg* m, uint16_t len);
        static void S_handle_dhcp(void* arg, struct udp_pcb* pcb, pbuf* p, const ip_addr_t* addr, uint16_t port);
        void handle_dhcp(udp_pcb* pcb, pbuf* p, const ip_addr_t* addr, uint16_t port);
        void kill_oldest_dhcps_pool();
        void dhcps_coarse_tmr();
        void dhcps_client_leave(uint8_t* bssid, ipv4_addr* ip, bool force);
        uint32_t dhcps_client_update(uint8_t* bssid, ipv4_addr* ip);

    protected:
               netif*      _netif;

        struct udp_pcb*    pcb_dhcps;
               ip_addr_t   broadcast_dhcps;

               ipv4_addr   server_address;
               ipv4_addr   client_address;
               ipv4_addr   dns_address;

               uint32_t    dhcps_lease_time;
        struct dhcps_lease dhcps_lease;

               list_node*  plist;
               uint8_t     offer;
               bool        renew;

        static const uint32_t magic_cookie;
};


} // namespace NodeMCU

} // namespace eCxx


//
// For compatibility with the Arduino library part
//
typedef eCxx::NodeMCU::DHCPServer DhcpServer;

// SoftAP DHCP server always exists and is started on boot
extern     eCxx::NodeMCU::DHCPServer dhcpSoftAP;
extern "C" int                       fw_has_started_softap_dhcps;


#endif
