package layer

import (
	"errors"
	"fmt"

	"github.com/sirupsen/logrus"
	"github.com/docker/distribution/digest"
	"github.com/docker/docker/daemon/graphdriver"
)

// GetLayerPath returns the path to a layer
func GetLayerPath(s Store, layer ChainID) (string, error) {
	ls, ok := s.(*layerStore)
	if !ok {
		return "", errors.New("unsupported layer store")
	}
	ls.layerL.Lock()
	defer ls.layerL.Unlock()

	rl, ok := ls.layerMap[layer]
	if !ok {
		return "", ErrLayerDoesNotExist
	}

	path, err := ls.driver.Get(rl.cacheID, "")
	if err != nil {
		return "", err
	}

	if err := ls.driver.Put(rl.cacheID); err != nil {
		return "", err
	}

	return path, nil
}

func (ls *layerStore) RegisterDiffID(graphID string, size int64) (Layer, error) {
	var err error // this is used for cleanup in existingLayer case
	diffID := digest.FromBytes([]byte(graphID))

	// Create new roLayer
	layer := &roLayer{
		cacheID:        graphID,
		diffID:         DiffID(diffID),
		referenceCount: 1,
		layerStore:     ls,
		references:     map[Layer]struct{}{},
		size:           size,
	}

	tx, err := ls.store.StartTransaction()
	if err != nil {
		return nil, err
	}
	defer func() {
		if err != nil {
			if err := tx.Cancel(); err != nil {
				logrus.Errorf("Error canceling metadata transaction %q: %s", tx.String(), err)
			}
		}
	}()

	layer.chainID = createChainIDFromParent("", layer.diffID)

	if !ls.driver.Exists(layer.cacheID) {
		return nil, fmt.Errorf("layer %q is unknown to driver", layer.cacheID)
	}
	if err = storeLayer(tx, layer); err != nil {
		return nil, err
	}

	ls.layerL.Lock()
	defer ls.layerL.Unlock()

	if existingLayer := ls.getWithoutLock(layer.chainID); existingLayer != nil {
		// Set error for cleanup, but do not return
		err = errors.New("layer already exists")
		return existingLayer.getReference(), nil
	}

	if err = tx.Commit(layer.chainID); err != nil {
		return nil, err
	}

	ls.layerMap[layer.chainID] = layer

	return layer.getReference(), nil
}

func (ls *layerStore) mountID(name string) string {
	// windows has issues if container ID doesn't match mount ID
	return name
}

func (ls *layerStore) GraphDriver() graphdriver.Driver {
	return ls.driver
}
