# `GanttEx.Link`
[🔗](https://github.com/rocket4ce/gantt_ex/blob/v0.1.0/lib/gantt_ex/link.ex#L1)

A dependency between two tasks.

The four dependency types of DHTMLX Gantt are supported:

| Type                | DHTMLX code | Meaning                                         |
| ------------------- | ----------- | ----------------------------------------------- |
| `:finish_to_start`  | `"0"`       | target starts after the source finishes         |
| `:start_to_start`   | `"1"`       | target starts after the source starts           |
| `:finish_to_finish` | `"2"`       | target finishes after the source finishes       |
| `:start_to_finish`  | `"3"`       | target finishes after the source starts         |

`:lag` is an integer amount of the chart's duration unit (negative values
are leads).

## Examples

    iex> {:ok, link} = GanttEx.Link.new(%{"id" => 1, "source" => 10, "target" => 11, "type" => "1"})
    iex> {link.source, link.target, link.type}
    {10, 11, :start_to_start}

    iex> {:ok, link} = GanttEx.Link.new(id: 2, source_id: 1, target_id: 2, lag: "2")
    iex> {link.type, link.lag}
    {:finish_to_start, 2}

    iex> GanttEx.Link.new(id: 3, source: 1)
    {:error, {:missing, :target}}

# `side`

```elixir
@type side() :: :start | :end
```

Which edge of a task bar a link is attached to.

# `t`

```elixir
@type t() :: %GanttEx.Link{
  color: String.t() | nil,
  id: GanttEx.Task.id(),
  lag: integer(),
  meta: map(),
  readonly: boolean(),
  source: GanttEx.Task.id(),
  target: GanttEx.Task.id(),
  type: type()
}
```

# `type`

```elixir
@type type() ::
  :finish_to_start | :start_to_start | :finish_to_finish | :start_to_finish
```

Dependency type.

# `cast_type`

```elixir
@spec cast_type(term()) :: {:ok, type()} | :error
```

Casts a link type from an atom, a DHTMLX code or a string.

    iex> GanttEx.Link.cast_type("2")
    {:ok, :finish_to_finish}

    iex> GanttEx.Link.cast_type(3)
    {:ok, :start_to_finish}

    iex> GanttEx.Link.cast_type("start_to_start")
    {:ok, :start_to_start}

    iex> GanttEx.Link.cast_type("sideways")
    :error

# `change`

```elixir
@spec change(t(), map() | keyword()) :: {:ok, t()} | {:error, GanttEx.Task.error()}
```

Applies `attrs` on top of an existing link. `:id`, `:source` and `:target`
cannot be changed.

    iex> link = GanttEx.Link.new!(id: 1, source: 1, target: 2)
    iex> {:ok, link} = GanttEx.Link.change(link, %{"type" => "finish_to_finish", "lag" => "-1"})
    iex> {link.type, link.lag}
    {:finish_to_finish, -1}

# `code`

```elixir
@spec code(type()) :: String.t()
```

Returns the DHTMLX numeric code of a link type.

    iex> GanttEx.Link.code(:start_to_start)
    "1"

# `new`

```elixir
@spec new(map() | keyword() | struct()) :: {:ok, t()} | {:error, GanttEx.Task.error()}
```

Builds a link from a map, keyword list or struct.

# `new!`

```elixir
@spec new!(map() | keyword() | struct()) :: t()
```

Like `new/1` but raises `ArgumentError` on invalid attributes.

    iex> GanttEx.Link.new!(id: 1, source: 1, target: 2).type
    :finish_to_start

# `sides`

```elixir
@spec sides(type()) :: {side(), side()}
```

Returns the `{source_side, target_side}` edges a link type connects.

    iex> GanttEx.Link.sides(:finish_to_start)
    {:end, :start}

    iex> GanttEx.Link.sides(:start_to_finish)
    {:start, :end}

# `to_map`

```elixir
@spec to_map(t(), keyword()) :: map()
```

Converts the link into a plain map, handy to persist it.

    iex> GanttEx.Link.new!(id: 1, source: 1, target: 2) |> GanttEx.Link.to_map() |> Map.take([:source, :target, :type])
    %{source: 1, target: 2, type: :finish_to_start}

# `type_for`

```elixir
@spec type_for(side(), side()) :: type()
```

Returns the link type that connects the given edges. This is how a link
drawn by dragging from one bar edge to another becomes a dependency.

    iex> GanttEx.Link.type_for(:end, :start)
    :finish_to_start

    iex> GanttEx.Link.type_for(:end, :end)
    :finish_to_finish

# `types`

```elixir
@spec types() :: [type()]
```

Returns the supported link types.

    iex> GanttEx.Link.types()
    [:finish_to_start, :start_to_start, :finish_to_finish, :start_to_finish]

---

*Consult [api-reference.md](api-reference.md) for complete listing*
