// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package main

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"time"

	"mojo/public/go/application"
	"mojo/public/go/bindings"
	"mojo/public/go/system"

	"mojo/services/network/interfaces/net_address"
	"mojo/services/network/interfaces/network_service"
	"mojo/services/network/interfaces/tcp_bound_socket"
	"mojo/services/network/interfaces/tcp_connected_socket"
	"mojo/services/network/interfaces/tcp_server_socket"
)

//#include "mojo/public/c/system/types.h"
import "C"

type MojoConnection struct {
	sendStream    system.ProducerHandle
	receiveStream system.ConsumerHandle
	socket        system.MessagePipeHandle
	localAddr     net.Addr
	remoteAddr    net.Addr
}

// Implements net.Conn.
func (c *MojoConnection) Read(b []byte) (int, error) {
	r, read := c.receiveStream.BeginReadData(system.MOJO_READ_DATA_FLAG_NONE)
	if r != system.MOJO_RESULT_OK {
		return 0, fmt.Errorf("can't read: %v", r)
	}
	l := len(b)
	if (l > len(read)) {
		l = len(read)
	}
	copy(b, read[:l])
	if r := c.receiveStream.EndReadData(l); r != system.MOJO_RESULT_OK {
		return 0, fmt.Errorf("can't read %v bytes: %v", l, r)
	}
	return l, nil
}

// Implements net.Conn.
func (c *MojoConnection) Write(b []byte) (int, error) {
	r, buf := c.sendStream.BeginWriteData(system.MOJO_WRITE_DATA_FLAG_NONE)
	if r != system.MOJO_RESULT_OK {
		return 0, fmt.Errorf("can't write: %v", r)
	}
	l := len(b)
	if l > len(buf) {
		l = len(buf)
	}
	copy(buf, b[:l])
	if r := c.sendStream.EndWriteData(l); r != system.MOJO_RESULT_OK {
		return 0, fmt.Errorf("can't write %v bytes: %v", l, r)
	}
	return l, nil
}

// Implements net.Conn.
func (c *MojoConnection) Close() error {
	c.sendStream.Close()
	c.receiveStream.Close()
	c.socket.Close()
	return nil
}

// Implements net.Conn.
func (c *MojoConnection) LocalAddr() net.Addr {
	return c.localAddr
}

// Implements net.Conn.
func (c *MojoConnection) RemoteAddr() net.Addr {
	return c.remoteAddr
}

// Implements net.Conn.
func (c *MojoConnection) SetDeadline(t time.Time) error {
	if err := c.SetReadDeadline(t); err != nil {
		return err
	}
	return c.SetWriteDeadline(t)
}

// Implements net.Conn.
func (c *MojoConnection) SetReadDeadline(t time.Time) error {
	// Do nothing.
	return nil
}

// Implements net.Conn.
func (c *MojoConnection) SetWriteDeadline(t time.Time) error {
	// Do nothing.
	return nil
}

type MojoListener struct {
	serverSocket *tcp_server_socket.TcpServerSocket_Proxy
}

// Implements net.Listener.
func (l *MojoListener) Accept() (net.Conn, error) {
	r, sendProducer, sendConsumer := system.GetCore().CreateDataPipe(nil)
	if r != system.MOJO_RESULT_OK {
		panic(fmt.Sprintf("can't create data pipe: %v", r))
	}
	r, receiveProducer, receiveConsumer := system.GetCore().CreateDataPipe(nil)
	if r != system.MOJO_RESULT_OK {
		panic(fmt.Sprintf("can't create data pipe: %v", r))
	}
	request, pointer := tcp_connected_socket.CreateMessagePipeForTcpConnectedSocket()
	networkError, remoteAddress, err := l.serverSocket.Accept(sendConsumer, receiveProducer, request)
	if err != nil {
		return nil, err
	}
	if networkError.Code != 0 {
		return nil, fmt.Errorf("%s", *networkError.Description)
	}

	var addr net.Addr
	if remoteAddress.Ipv4 != nil {
		addr = &net.TCPAddr{
			IP:   remoteAddress.Ipv4.Addr[:4],
			Port: int(remoteAddress.Ipv4.Port),
		}
	} else {
		addr = &net.TCPAddr{
			IP:   remoteAddress.Ipv6.Addr[:16],
			Port: int(remoteAddress.Ipv6.Port),
		}
	}
	return &MojoConnection{
		sendProducer,
		receiveConsumer,
		pointer.PassMessagePipe(),
		l.Addr(),
		addr,
	}, nil
}

// Implements net.Listener.
func (l *MojoListener) Close() error {
	l.serverSocket.Close_Proxy()
	return nil
}

// Implements net.Listener.
func (l *MojoListener) Addr() net.Addr {
	return &net.TCPAddr{
		IP:   []byte{127, 0, 0, 1},
		Port: 8080,
	}
}

type HttpServerDelegate struct {
	networkService *network_service.NetworkService_Proxy
	tcpBoundSocket *tcp_bound_socket.TcpBoundSocket_Proxy
	serverSocket   *tcp_server_socket.TcpServerSocket_Proxy
}

func (d *HttpServerDelegate) InitTCPBoundSocket() error {
	addr := &net_address.NetAddress{
		net_address.NetAddressFamily_IpV4,
		&net_address.NetAddressIPv4{
			8080,
			[4]uint8{127, 0, 0, 1},
		},
		nil,
	}
	request, pointer := tcp_bound_socket.CreateMessagePipeForTcpBoundSocket()
	networkError, _, err := d.networkService.CreateTcpBoundSocket(addr, request)
	if err != nil {
		return err
	}
	if networkError.Code != 0 {
		return fmt.Errorf("%s", *networkError.Description)
	}
	d.tcpBoundSocket = tcp_bound_socket.NewTcpBoundSocketProxy(pointer, bindings.GetAsyncWaiter())
	return nil
}

func (d *HttpServerDelegate) InitServerSocket() error {
	request, pointer := tcp_server_socket.CreateMessagePipeForTcpServerSocket()
	networkError, err := d.tcpBoundSocket.StartListening(request)
	if err != nil {
		return err
	}
	if networkError.Code != 0 {
		return fmt.Errorf("%s", *networkError.Description)
	}
	d.serverSocket = tcp_server_socket.NewTcpServerSocketProxy(pointer, bindings.GetAsyncWaiter())
	return nil
}

func (d *HttpServerDelegate) Initialize(ctx application.Context) {
	request, pointer := network_service.CreateMessagePipeForNetworkService()
	ctx.ConnectToApplication("mojo:network_service").ConnectToService(&request)
	d.networkService = network_service.NewNetworkServiceProxy(pointer, bindings.GetAsyncWaiter())

	if err := d.InitTCPBoundSocket(); err != nil {
		log.Printf("can't create TCP socket: %v\n", err)
		return
	}
	if err := d.InitServerSocket(); err != nil {
		log.Printf("can't create server socket: %v\n", err)
		return
	}

	http.HandleFunc("/go", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello, Go http server!")
	})
	l := &MojoListener{d.serverSocket}
	if err := http.Serve(l, nil); err != nil {
		log.Printf("can't serve request: %v\n", err)
		return
	}
}

func (d *HttpServerDelegate) AcceptConnection(c *application.Connection) {
	c.Close()
}

func (d *HttpServerDelegate) Quit() {
	d.networkService.Close_Proxy()
	d.tcpBoundSocket.Close_Proxy()
	d.serverSocket.Close_Proxy()
}

//export MojoMain
func MojoMain(handle C.MojoHandle) C.MojoResult {
	application.Run(&HttpServerDelegate{}, system.MojoHandle(handle))
	return C.MOJO_RESULT_OK
}

func main() {
}
