// Copyright 2013 The Go 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 httpfs implements http.FileSystem using a godoc vfs.FileSystem.
package httpfs // import "golang.org/x/tools/godoc/vfs/httpfs"

import (
	"fmt"
	"io"
	"net/http"
	"os"

	"golang.org/x/tools/godoc/vfs"
)

func New(fs vfs.FileSystem) http.FileSystem {
	return &httpFS{fs}
}

type httpFS struct {
	fs vfs.FileSystem
}

func (h *httpFS) Open(name string) (http.File, error) {
	fi, err := h.fs.Stat(name)
	if err != nil {
		return nil, err
	}
	if fi.IsDir() {
		return &httpDir{h.fs, name, nil}, nil
	}
	f, err := h.fs.Open(name)
	if err != nil {
		return nil, err
	}
	return &httpFile{h.fs, f, name}, nil
}

// httpDir implements http.File for a directory in a FileSystem.
type httpDir struct {
	fs      vfs.FileSystem
	name    string
	pending []os.FileInfo
}

func (h *httpDir) Close() error               { return nil }
func (h *httpDir) Stat() (os.FileInfo, error) { return h.fs.Stat(h.name) }
func (h *httpDir) Read([]byte) (int, error) {
	return 0, fmt.Errorf("cannot Read from directory %s", h.name)
}

func (h *httpDir) Seek(offset int64, whence int) (int64, error) {
	if offset == 0 && whence == 0 {
		h.pending = nil
		return 0, nil
	}
	return 0, fmt.Errorf("unsupported Seek in directory %s", h.name)
}

func (h *httpDir) Readdir(count int) ([]os.FileInfo, error) {
	if h.pending == nil {
		d, err := h.fs.ReadDir(h.name)
		if err != nil {
			return nil, err
		}
		if d == nil {
			d = []os.FileInfo{} // not nil
		}
		h.pending = d
	}

	if len(h.pending) == 0 && count > 0 {
		return nil, io.EOF
	}
	if count <= 0 || count > len(h.pending) {
		count = len(h.pending)
	}
	d := h.pending[:count]
	h.pending = h.pending[count:]
	return d, nil
}

// httpFile implements http.File for a file (not directory) in a FileSystem.
type httpFile struct {
	fs vfs.FileSystem
	vfs.ReadSeekCloser
	name string
}

func (h *httpFile) Stat() (os.FileInfo, error) { return h.fs.Stat(h.name) }
func (h *httpFile) Readdir(int) ([]os.FileInfo, error) {
	return nil, fmt.Errorf("cannot Readdir from file %s", h.name)
}
