# Path: zutils/py_utils.py
# def path_full_split(p):
#     s = list()
#     a = p
#     if not a:
#         return s
#     if a[-1] == "/":
#         s.append("")
#         while a and a[-1] == "/":
#             a = a[:-1]
#     while True:
#         [a, b] = os.path.split(a)
#         if b:
#             s.append(b)
#         else:
#             if a:
#                 s.append(a)
#             else:
#                 break
#     s.reverse()
#     return s
# 
# def value_class_for_with(init_value=None):
# 
#     class value_for_with:
# 
#         current_value = init_value
# 
#         def __init__(self, value):
#             self._value = value
#             self._upper_value = None
# 
#         def __enter__(self):
#             self._upper_value = value_for_with.current_value
#             value_for_with.current_value = self._value
#             return self
# 
#         def __exit__(self, exc_type, exc_val, exc_tb):
#             value_for_with.current_value = self._upper_value
#             return False
# 
#     return value_for_with


import tensorflow as tf
import stat
import numpy as np
import re
import os
from tensorflow.python.lib.io import file_io
from collections import OrderedDict, Iterable
from copy import copy
from types import MethodType
from zutils.py_utils import path_full_split, value_class_for_with
from tensorflow.python.client import device_lib

def copy_vars_between_scope(src, dst, src_vars=None, dst_vars=None):
    pair_list = pair_vars_between_scope(src=src, dst=dst, src_vars=src_vars, dst_vars=dst_vars)
    return copy_vars_per_pair_list(pair_list)


def ruleout_shared_vars(var_list):
    shared_pair_list = tf.get_collection("variable_sharing")
    var_list = set(var_list) - set(dst_v for _, dst_v in shared_pair_list)
    var_list = list(var_list)
    return var_list


def update_shared_vars(var_list=None):
    shared_pair_list = tf.get_collection("variable_sharing")
    if var_list is not None:
        var_list = set(var_list)
        shared_pair_list = list(filter(lambda x: x[1] in var_list, shared_pair_list))
    return copy_vars_per_pair_list(shared_pair_list)


# ----------------------------------------------------------------------------------------------------------------


def match_scope(item, scope_path):
    if isinstance(item, tf.Variable):
        # exact match
        return item.name.startswith(scope_path)
    else:
        # robust match

# Path: zutils/py_utils.py
# def path_full_split(p):
#     s = list()
#     a = p
#     if not a:
#         return s
#     if a[-1] == "/":
#         s.append("")
#         while a and a[-1] == "/":
#             a = a[:-1]
#     while True:
#         [a, b] = os.path.split(a)
#         if b:
#             s.append(b)
#         else:
#             if a:
#                 s.append(a)
#             else:
#                 break
#     s.reverse()
#     return s
# 
# def value_class_for_with(init_value=None):
# 
#     class value_for_with:
# 
#         current_value = init_value
# 
#         def __init__(self, value):
#             self._value = value
#             self._upper_value = None
# 
#         def __enter__(self):
#             self._upper_value = value_for_with.current_value
#             value_for_with.current_value = self._value
#             return self
# 
#         def __exit__(self, exc_type, exc_val, exc_tb):
#             value_for_with.current_value = self._upper_value
#             return False
# 
#     return value_for_with


# Path: zutils/tf_graph_utils.py
import tensorflow as tf
import stat
import numpy as np
import re
import os
from tensorflow.python.lib.io import file_io
from collections import OrderedDict, Iterable
from copy import copy
from types import MethodType
from zutils.py_utils import path_full_split, value_class_for_with
from tensorflow.python.client import device_lib


def copy_vars_between_scope(src, dst, src_vars=None, dst_vars=None):
    pair_list = pair_vars_between_scope(src=src, dst=dst, src_vars=src_vars, dst_vars=dst_vars)
    return copy_vars_per_pair_list(pair_list)


def ruleout_shared_vars(var_list):
    shared_pair_list = tf.get_collection("variable_sharing")
    var_list = set(var_list) - set(dst_v for _, dst_v in shared_pair_list)
    var_list = list(var_list)
    return var_list


def update_shared_vars(var_list=None):
    shared_pair_list = tf.get_collection("variable_sharing")
    if var_list is not None:
        var_list = set(var_list)
        shared_pair_list = list(filter(lambda x: x[1] in var_list, shared_pair_list))
    return copy_vars_per_pair_list(shared_pair_list)


# ----------------------------------------------------------------------------------------------------------------


def match_scope(item, scope_path):
    if isinstance(item, tf.Variable):
        # exact match
        return item.name.startswith(scope_path)
    else:
        # robust match

        t = path_full_split(item.name)