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

// +build !build_with_native_toolchain

package component

import (
	"fmt"
	"sync"
	"syscall/zx"
	"syscall/zx/fdio"
	"syscall/zx/fidl"

	"fidl/fuchsia/io"
	"fidl/fuchsia/sys"
)

// #include "zircon/process.h"
import "C"

const (
	HandleDirectoryRequest HandleType = 0x3B
	HandleAppServices      HandleType = 0x43

	HandleUser0 HandleType = 0xF0
	HandleUser1 HandleType = 0xF1
	HandleUser2 HandleType = 0xF2
)

type HandleType uint16

type HandleInfo struct {
	Type HandleType
	Arg  uint16
}

func GetStartupHandle(info HandleInfo) zx.Handle {
	id := uint32(info.Arg)<<16 | uint32(info.Type)
	h := C.zx_take_startup_handle(C.uint32_t(id))
	return zx.Handle(h)
}

type Connector struct {
	serviceRoot zx.Handle
}

type OutDirectory mapDirectory

func (od OutDirectory) getMapDirectory(name string) mapDirectory {
	if dir, ok := od[name]; ok {
		if dir, ok := dir.(*DirectoryWrapper); ok {
			if dir, ok := dir.Directory.(mapDirectory); ok {
				return dir
			}
			panic(fmt.Sprintf("unexpected %s type %T", name, dir))
		}
		panic(fmt.Sprintf("unexpected %s type %T", name, dir))
	}
	dir := make(mapDirectory)
	od[name] = &DirectoryWrapper{
		Directory: dir,
	}
	return dir
}

func (od OutDirectory) AddDebug(name string, n Node) {
	od.getMapDirectory("debug")[name] = n
}

func (od OutDirectory) AddDiagnostics(name string, n Node) {
	od.getMapDirectory("diagnostics")[name] = n
}

func (od OutDirectory) AddService(name string, addFn addFn) {
	od.getMapDirectory("svc")[name] = &Service{AddFn: addFn}
}

type Context struct {
	connector   Connector
	environment struct {
		sync.Once
		*sys.EnvironmentWithCtxInterface
	}
	launcher struct {
		sync.Once
		*sys.LauncherWithCtxInterface
	}
	// OutgoingService is the directory served on the startup directory request.
	//
	// OutgoingService is cleared when BindStartupHandle is called to prevent further mutation which
	// is not supported by this implementation, though it is permitted by fuchsia.io.Directory.
	OutgoingService OutDirectory
}

// NewContextFromStartupInfo connects to the service root directory and registers
// debug services.
func NewContextFromStartupInfo() *Context {
	c0, c1, err := zx.NewChannel(0)
	if err != nil {
		panic(err)
	}

	// TODO(tamird): use "/svc" once it no longer causes crashes.
	if err := fdio.ServiceConnect("/svc/.", zx.Handle(c0)); err != nil {
		panic(err)
	}
	c := &Context{
		connector: Connector{
			serviceRoot: zx.Handle(c1),
		},
		OutgoingService: make(OutDirectory),
	}

	c.OutgoingService.AddDebug("pprof", &DirectoryWrapper{Directory: &pprofDirectory{}})
	c.OutgoingService.AddDebug("goroutines", &FileWrapper{File: &stackTraceFile{}})

	return c
}

// BindStartupHandle takes the startup handle if it's not already taken and
// serves the out directory with all services that have been registered on
// (*Context).OutgoingService.
//
// New services must not be added after BindStartupHandle is called.
//
// BindStartupHandle blocks until the context is canceled.
func (c *Context) BindStartupHandle(ctx fidl.Context) {
	directory := mapDirectory(c.OutgoingService)
	// Prevent further mutation.
	c.OutgoingService = nil
	if directoryRequest := GetStartupHandle(HandleInfo{
		Type: HandleDirectoryRequest,
		Arg:  0,
	}); directoryRequest.IsValid() {
		if err := (&DirectoryWrapper{
			Directory: directory,
		}).addConnection(ctx, 0, 0, io.NodeWithCtxInterfaceRequest{
			Channel: zx.Channel(directoryRequest),
		}); err != nil {
			panic(err)
		}
	}
	<-ctx.Done()
}

func (c *Context) Connector() *Connector {
	return &c.connector
}

func (c *Context) Environment() *sys.EnvironmentWithCtxInterface {
	c.environment.Do(func() {
		r, p, err := sys.NewEnvironmentWithCtxInterfaceRequest()
		if err != nil {
			panic(err)
		}
		c.environment.EnvironmentWithCtxInterface = p
		c.Connector().ConnectToEnvService(r)
	})
	return c.environment.EnvironmentWithCtxInterface
}

func (c *Context) Launcher() *sys.LauncherWithCtxInterface {
	c.launcher.Do(func() {
		r, p, err := sys.NewLauncherWithCtxInterfaceRequest()
		if err != nil {
			panic(err)
		}
		c.launcher.LauncherWithCtxInterface = p
		c.Connector().ConnectToEnvService(r)
	})
	return c.launcher.LauncherWithCtxInterface
}

func (c *Context) ConnectToEnvService(r fidl.ServiceRequest) {
	c.Connector().ConnectToEnvService(r)
}

func (c *Connector) ConnectToEnvService(r fidl.ServiceRequest) {
	if err := fdio.ServiceConnectAt(c.serviceRoot, r.Name(), zx.Handle(r.ToChannel())); err != nil {
		panic(err)
	}
}
