// Copyright (c) 2012, 2015 Kiel University and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0.
//
// SPDX-License-Identifier: EPL-2.0

package components

import (
	basegraph 
	
)

// ELK represents an external-port side set as an EnumSet. The arena stores
// the same set as a bit mask whose bit index is PortSide's ordinal.
const (
	sidesNone  uint8 = 0
	sidesNorth uint8 = 1 << uint8(layered.NorthSide)
	sidesEast  uint8 = 1 << uint8(layered.EastSide)
	sidesSouth uint8 = 1 << uint8(layered.SouthSide)
	sidesWest  uint8 = 1 << uint8(layered.WestSide)

	sidesNorthEast          = sidesNorth | sidesEast
	sidesNorthSouth         = sidesNorth | sidesSouth
	sidesNorthWest          = sidesNorth | sidesWest
	sidesEastSouth          = sidesEast | sidesSouth
	sidesEastWest           = sidesEast | sidesWest
	sidesSouthWest          = sidesSouth | sidesWest
	sidesNorthEastSouth     = sidesNorth | sidesEast | sidesSouth
	sidesNorthEastWest      = sidesNorth | sidesEast | sidesWest
	sidesNorthSouthWest     = sidesNorth | sidesSouth | sidesWest
	sidesEastSouthWest      = sidesEast | sidesSouth | sidesWest
	sidesNorthEastSouthWest = sidesNorth | sidesEast | sidesSouth | sidesWest
)

// componentConstraints is ComponentGroup.CONSTRAINTS. The map is deliberately
// directional: the key is the candidate being inserted and each value is a
// side combination that must not already occur in the group.
var componentConstraints = map[uint8][]uint8{
	sidesNone:               {sidesNorthEastSouthWest},
	sidesWest:               {sidesNorthEastSouthWest, sidesNorthSouthWest},
	sidesEast:               {sidesNorthEastSouth, sidesNorthEastSouthWest},
	sidesNorth:              {sidesNorthEastSouthWest, sidesNorthEastWest},
	sidesSouth:              {sidesEastSouthWest, sidesNorthEastSouthWest},
	sidesNorthSouth:         {sidesEastWest, sidesNorthEastSouthWest, sidesNorthEastWest, sidesEastSouthWest},
	sidesEastWest:           {sidesNorthSouth, sidesNorthSouthWest, sidesNorthEastSouth, sidesNorthEastSouthWest},
	sidesNorthWest:          {sidesNorthWest, sidesNorthEastWest, sidesNorthSouthWest},
	sidesNorthEast:          {sidesNorthEast, sidesNorthEastWest, sidesNorthEastSouth},
	sidesSouthWest:          {sidesSouthWest, sidesEastSouthWest, sidesNorthSouthWest},
	sidesEastSouth:          {sidesEastSouth, sidesEastSouthWest, sidesNorthEastSouth},
	sidesNorthEastWest:      {sidesNorth, sidesNorthSouth, sidesNorthWest, sidesNorthEast, sidesNorthEastSouthWest, sidesNorthEastWest, sidesNorthSouthWest, sidesNorthEastSouth},
	sidesEastSouthWest:      {sidesSouth, sidesNorthSouth, sidesSouthWest, sidesEastSouth, sidesEastSouthWest, sidesNorthSouthWest, sidesNorthEastSouth, sidesNorthEastSouthWest},
	sidesNorthSouthWest:     {sidesWest, sidesEastWest, sidesNorthWest, sidesSouthWest, sidesNorthEastWest, sidesEastSouthWest, sidesNorthSouthWest, sidesNorthEastSouthWest},
	sidesNorthEastSouth:     {sidesEast, sidesEastWest, sidesNorthEast, sidesEastSouth, sidesNorthEastWest, sidesEastSouthWest, sidesNorthEastSouth, sidesNorthEastSouthWest},
	sidesNorthEastSouthWest: {sidesNone, sidesWest, sidesEast, sidesNorth, sidesSouth, sidesNorthSouth, sidesEastWest, sidesNorthEastWest, sidesEastSouthWest, sidesNorthSouthWest, sidesNorthEastSouth, sidesNorthEastSouthWest},
}

type componentGroup struct {
	componentsBySides map[uint8][]layered.LGraphID
	sideOrder         []uint8
}

func newComponentGroup(
	 *layered.LGraphArena,
	 layered.LGraphID,
) *componentGroup {
	 := &componentGroup{componentsBySides: make(map[uint8][]layered.LGraphID)}
	.add(, )
	return 
}

func ( *componentGroup) (
	 *layered.LGraphArena,
	 layered.LGraphID,
) bool {
	if !.canAdd(, , nil) {
		return false
	}
	.insert(, )
	return true
}

func ( *componentGroup) (
	 *layered.LGraphArena,
	 layered.LGraphID,
	 map[uint8][]uint8,
) bool {
	 := basegraph.Get(
		&.Graph().Properties, layered.ExternalPortConnections)
	for ,  := range [...][]uint8{
		componentConstraints[], [],
	} {
		for ,  := range  {
			if len(.componentsBySides[]) != 0 {
				return false
			}
		}
	}
	return true
}

func ( *componentGroup) (
	 *layered.LGraphArena,
	 layered.LGraphID,
) {
	 := basegraph.Get(
		&.Graph().Properties, layered.ExternalPortConnections)
	if len(.componentsBySides[]) == 0 {
		.sideOrder = append(.sideOrder, )
	}
	.componentsBySides[] = append(.componentsBySides[], )
}

func ( *componentGroup) ( uint8) []layered.LGraphID {
	return .componentsBySides[]
}

func ( *componentGroup) () []layered.LGraphID {
	 := make([]layered.LGraphID, 0)
	for ,  := range .sideOrder {
		 = append(, .componentsBySides[]...)
	}
	return 
}

func ( *componentGroup) () []uint8 {
	return .sideOrder
}