1d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets/*
21503d52153986fdcfe7e744795010708b7410892Ian Lake * Copyright 2018 The Android Open Source Project
3d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets *
4d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets * Licensed under the Apache License, Version 2.0 (the "License");
5d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets * you may not use this file except in compliance with the License.
6d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets * You may obtain a copy of the License at
7d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets *
8d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets *      http://www.apache.org/licenses/LICENSE-2.0
9d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets *
10d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets * Unless required by applicable law or agreed to in writing, software
11d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets * distributed under the License is distributed on an "AS IS" BASIS,
12d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets * See the License for the specific language governing permissions and
14d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets * limitations under the License.
15d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets */
16d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets
171503d52153986fdcfe7e744795010708b7410892Ian Lakepackage androidx.navigation.safe.args.generator
18d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets
191503d52153986fdcfe7e744795010708b7410892Ian Lakeimport androidx.navigation.safe.args.generator.models.Argument
201503d52153986fdcfe7e744795010708b7410892Ian Lakeimport androidx.navigation.safe.args.generator.models.Destination
211503d52153986fdcfe7e744795010708b7410892Ian Lakeimport androidx.navigation.safe.args.generator.models.ResReference
22d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets
23d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinetsfun resolveArguments(rootDestination: Destination): Destination {
249ca584405af88767f97ec06fbb5f5e1b7e98b1b4Sergey Vasilinets    val destinations = mutableMapOf<ResReference, Destination>()
25d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets
26d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets    fun dfs(dest: Destination): Destination {
27d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets        val nested = dest.nested.filter { it.id != null }.associateBy { it.id!! }
28d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets        destinations.putAll(nested)
29d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets        val resolvedActions = dest.actions.map { action ->
30d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets            val actionDestination = destinations[action.destination]
31d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets            if (actionDestination != null) {
32d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets                action.copy(args = mergeArguments(action.args, actionDestination.args))
33d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets            } else {
34d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets                action
35d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets            }
36d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets        }
37d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets        val result = dest.copy(nested = dest.nested.map(::dfs), actions = resolvedActions)
38d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets        nested.keys.forEach { id -> destinations.remove(id) }
39d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets        return result
40d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets    }
41d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets
42d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets    return dfs(rootDestination)
43d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets}
44d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets
45d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinetsprivate fun mergeArguments(args1: List<Argument>, args2: List<Argument>) =
46d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets        args2.fold(args1) { result, arg ->
47d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets            val duplicate = result.find { it.name == arg.name }
48d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets            if (duplicate != null) {
49d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets                if (duplicate.type != arg.type) {
50d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets                    // TODO: needs context to print better exception
51d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets                    throw IllegalArgumentException("Incompatible types ${duplicate.type} and " +
52f49d36a214375ac9a735ab9af9e1b3a4b9d2a3cdSergey Vasilinets                            "${arg.type} of argument ${arg.name}")
53d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets                }
54d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets                result
55d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets            } else {
56d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets                result + arg
57d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets            }
58d88974530aa8463cd0d66cdc7ff8bf77ca7fca72Sergey Vasilinets        }
59