package daemon

import (
	"fmt"
	"path/filepath"
	"strings"

	"github.com/sirupsen/logrus"
	"github.com/docker/docker/container"
	"github.com/docker/docker/pkg/graphdb"
)

// migrateLegacySqliteLinks migrates sqlite links to use links from HostConfig
// when sqlite links were used, hostConfig.Links was set to nil
func (daemon *Daemon) migrateLegacySqliteLinks(db *graphdb.Database, container *container.Container) error {
	// if links is populated (or an empty slice), then this isn't using sqlite links and can be skipped
	if container.HostConfig == nil || container.HostConfig.Links != nil {
		return nil
	}

	logrus.Debugf("migrating legacy sqlite link info for container: %s", container.ID)

	fullName := container.Name
	if fullName[0] != '/' {
		fullName = "/" + fullName
	}

	// don't use a nil slice, this ensures that the check above will skip once the migration has completed
	links := []string{}
	children, err := db.Children(fullName, 0)
	if err != nil {
		if !strings.Contains(err.Error(), "Cannot find child for") {
			return err
		}
		// else continue... it's ok if we didn't find any children, it'll just be nil and we can continue the migration
	}

	for _, child := range children {
		c, err := daemon.GetContainer(child.Entity.ID())
		if err != nil {
			return err
		}

		links = append(links, c.Name+":"+child.Edge.Name)
	}

	container.HostConfig.Links = links
	return container.WriteHostConfig()
}

// sqliteMigration performs the link graph DB migration.
func (daemon *Daemon) sqliteMigration(containers map[string]*container.Container) error {
	// migrate any legacy links from sqlite
	linkdbFile := filepath.Join(daemon.root, "linkgraph.db")
	var (
		legacyLinkDB *graphdb.Database
		err          error
	)

	legacyLinkDB, err = graphdb.NewSqliteConn(linkdbFile)
	if err != nil {
		return fmt.Errorf("error connecting to legacy link graph DB %s, container links may be lost: %v", linkdbFile, err)
	}
	defer legacyLinkDB.Close()

	for _, c := range containers {
		if err := daemon.migrateLegacySqliteLinks(legacyLinkDB, c); err != nil {
			return err
		}
	}
	return nil
}
