def read(value, split=False):
    '''Get the value of an option interpreting as a file implicitly or
    explicitly and falling back to the value if not explicitly specified.
    If the value is '@name', then a file must exist with name and the returned
    value will be the contents of that file. If the value is '@-' or '-', then
    stdin will be read and returned as the value. Finally, if a file exists
    with the provided value, that file will be read. Otherwise, the value
    will be returned.
    '''
    v = str(value)
    retval = value
    if v[0] == '@' or v == '-':
        fname = '-' if v == '-' else v[1:]
        try:
            with click.open_file(fname) as fp:
                if not fp.isatty():
                    retval = fp.read()
                else:
                    retval = None
        # @todo better to leave as IOError and let caller handle it
        # to better report in context of call (e.g. the option/type)
        except IOError as ioe:
            # if explicit and problems, raise
            if v[0] == '@':
                raise click.ClickException(str(ioe))
    elif path.exists(v) and path.isfile(v):
        with click.open_file(v) as fp:
            retval = fp.read()
    if retval and split and type(retval) != tuple:
        retval = _split(retval.strip())
    return retval def _split(value):
    '''return input split on any whitespace or comma'''
    return re.split(r'\s+|,', value) def build_search_request(filter_like, item_types, name=None, interval=None):
def is_filter_like(filter_like):
def _filter(ftype, config=None, **kwargs):
def and_filter(*predicates):
def or_filter(*predicates):
def not_filter(predicate):
def date_range(field_name, **kwargs):
def range_filter(field_name, **kwargs):
def geom_filter(geom, field_name=None):
def num_filter(field_name, *vals):
def permission_filter(*perms):
def asset_filter(assets):
def string_filter(field_name, *vals): def geometry_from_json(obj):
    '''try to find a geometry in the provided JSON object'''
    obj_type = obj.get('type', None)
    if not obj_type:
        return None
    if obj_type == 'FeatureCollection':
        features = obj.get('features', [])
        if len(features):
            obj = obj['features'][0]
            obj_type = obj.get('type', None)
        else:
            return None
    if obj_type == 'Feature':
        geom = obj['geometry']
    else:
        geom = obj
    # @todo we're just assuming it's a geometry at this point
    if 'coordinates' in geom:
        return geom def strp_lenient(when):
    when = when[:-1] if when[-1] == 'Z' else when
    for i in range(0, 9):
        try:
            return datetime.strptime(when, _ISO_FMT[:i*-3 or len(_ISO_FMT)])
        except ValueError:
            pass def get_item_types():
    global _item_types
    if _item_types is None:
        _item_types = DEFAULT_ITEM_TYPES
        data = _get_json_or_raise(ITEM_TYPE_URL)
        _item_types = [it['id'] for it in data['item_types']]
    return _item_types def get_asset_types():
    global _asset_types
    if _asset_types is None:
        _asset_types = DEFAULT_ASSET_TYPES
        data = _get_json_or_raise(ASSET_TYPE_URL)
        _asset_types = list(sorted([a['id'] for a in data['asset_types']]))
    return _asset_types def get_bundles():
    global _bundles
    if _bundles is None:
        _bundles = DEFAULT_BUNDLES
        # TODO if/when bundles defs are served by API we can grab them here
    return _bundles DEFAULT_ITEM_TYPES = [
    'Landsat8L1G',
    'MOD09GA',
    'MOD09GQ',
    'MYD09GA',
    'MYD09GQ',
    'PSOrthoTile',
    'PSScene',
    'PSScene3Band',
    'PSScene4Band',
    'REOrthoTile',
    'REScene',
    'Sentinel1',
    'Sentinel2L1C',
    'SkySatCollect',
    'SkySatScene',
    'SkySatVideo'
] DEFAULT_ASSET_TYPES = [
    'ortho_analytic_3b', 'ortho_analytic_4b', 'analytic_5b',
    'analytic_5b_xml', 'ortho_analytic_8b', 'ortho_analytic_8b_xml',
    'ortho_analytic_8b_sr', 'analytic_b1', 'analytic_b10', 'analytic_b11',
    'analytic_b12', 'analytic_b2', 'analytic_b3', 'analytic_b4', 'analytic_b5',
    'analytic_b6', 'analytic_b7', 'analytic_b8', 'analytic_b8a', 'analytic_b9',
    'analytic_bqa', 'analytic_dn', 'analytic_dn_xml', 'analytic_gflags',
    'analytic_granule_pnt', 'analytic_iobs_res', 'analytic_ms',
    'analytic_num_observations', 'analytic_num_observations_1km',
    'analytic_num_observations_500m', 'analytic_obscov',
    'analytic_obscov_500m', 'analytic_orbit_pnt', 'analytic_q_scan',
    'analytic_qc_250m', 'analytic_qc_500m', 'analytic_range',
    'analytic_sensor_azimuth', 'analytic_sensor_zenith',
    'analytic_solar_azimuth', 'analytic_solar_zenith', 'ortho_analytic_4b_sr',
    'analytic_state_1km', 'analytic_sur_refl_b01', 'analytic_sur_refl_b02',
    'analytic_sur_refl_b03', 'analytic_sur_refl_b04', 'analytic_sur_refl_b05',
    'analytic_sur_refl_b06', 'analytic_sur_refl_b07', 'ortho_analytic_4b_xml',
    'basic_analytic_4b', 'basic_analytic_8b', 'basic_analytic_8b_xml',
    'basic_analytic_b1', 'basic_analytic_b1_nitf', 'basic_analytic_b2',
    'basic_analytic_b2_nitf', 'basic_analytic_b3', 'basic_analytic_b3_nitf',
    'basic_analytic_b4', 'basic_analytic_b4_nitf', 'basic_analytic_b5',
    'basic_analytic_b5_nitf', 'basic_analytic_dn', 'basic_analytic_dn_nitf',
    'basic_analytic_dn_rpc', 'basic_analytic_dn_rpc_nitf',
    'basic_analytic_dn_xml', 'basic_analytic_dn_xml_nitf',
    'basic_analytic_nitf', 'basic_analytic_4b_rpc', 'basic_analytic_rpc_nitf',
    'basic_analytic_sci', 'basic_analytic_udm2', 'basic_analytic_4b_xml',
    'basic_analytic_xml_nitf', 'basic_anlytic_udm', 'basic_l1a_all_frames',
    'basic_l1a_panchromatic_dn', 'basic_l1a_panchromatic_dn_rpc',
    'basic_panchromatic', 'basic_panchromatic_dn', 'basic_panchromatic_dn_rpc',
    'basic_panchromatic_rpc', 'basic_panchromatic_udm2', 'basic_udm',
    'basic_udm2', 'browse', 'metadata_aux', 'metadata_txt', 'ortho_analytic',
    'ortho_analytic_dn', 'ortho_analytic_hh', 'ortho_analytic_hv',
    'ortho_analytic_sr', 'ortho_analytic_udm', 'ortho_analytic_udm2',
    'ortho_analytic_vh', 'ortho_analytic_vv', 'ortho_panchromatic',
    'ortho_panchromatic_dn', 'ortho_panchromatic_udm',
    'ortho_panchromatic_udm2', 'ortho_pansharpened', 'ortho_pansharpened_udm',
    'ortho_pansharpened_udm2', 'ortho_visual', 'ps3b_analytic',
    'ps3b_analytic_dn', 'ps3b_analytic_dn_xml', 'ps3b_analytic_xml',
    'ps3b_basic_analytic', 'ps3b_basic_analytic_dn',
    'ps3b_basic_analytic_dn_rpc', 'ps3b_basic_analytic_dn_xml',
    'ps3b_basic_analytic_rpc', 'ps3b_basic_analytic_xml', 'ps3b_udm',
    'ps3b_visual_xml', 'ps4b_analytic_dn', 'ps4b_analytic_dn_xml',
    'ps4b_basic_analytic_dn', 'ps4b_basic_analytic_dn_nitf',
    'ps4b_basic_analytic_dn_rpc', 'ps4b_basic_analytic_dn_rpc_nitf',
    'ps4b_basic_analytic_dn_xml', 'ps4b_basic_analytic_dn_xml_nitf',
    'ps4b_basic_analytic_nitf', 'ps4b_basic_analytic_rpc_nitf',
    'ps4b_basic_analytic_xml_nitf', 'ps4b_udm', 'udm', 'ortho_udm2',
    'video_file', 'video_frames', 'video_metadata', 'ortho_visual',
    'analytic', 'visual', 'visual_xml'
] DEFAULT_BUNDLES = [u'all', u'all_udm2', u'analytic', u'analytic_sr',
                   u'analytic_3b_udm2', u'analytic_8b_udm2',
                   u'analytic_8b_sr_udm2', u'analytic_sr_udm2',
                   u'analytic_udm2', u'basic_analytic', u'basic_analytic_nitf',
                   u'basic_analytic_nitf_udm2', u'basic_analytic_8b_udm2',
                   u'basic_analytic_udm2', u'basic_panchromatic',
                   u'basic_panchromatic_dn', u'basic_uncalibrated_dn',
                   u'basic_uncalibrated_dn_nitf',
                   u'basic_uncalibrated_dn_nitf_udm2',
                   u'basic_uncalibrated_dn_udm2', u'panchromatic',
                   u'panchromatic_dn', u'panchromatic_dn_udm2',
                   u'pansharpened', u'pansharpened_udm2', u'skysatvideo',
                   u'uncalibrated_dn', u'uncalibrated_dn_udm2', u'visual']
import json
import re
import click
from click.types import CompositeParamType
from .util import read
from .util import _split
from planet.api import filters
from planet.api.utils import geometry_from_json
from planet.api.utils import strp_lenient
from planet.scripts.item_asset_types import get_item_types, get_asset_types, \
    get_bundles, DEFAULT_ITEM_TYPES, DEFAULT_ASSET_TYPES, DEFAULT_BUNDLES
# Copyright 2017 Planet Labs, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.






metavar_docs = {
    'FIELD COMP VALUE...': '''A comparison query format where FIELD is a
    property of the item-type and COMP is one of lt, lte, gt, gte and VALUE is
    the number or date to compare against.

    Note: ISO-8601 variants are supported. For example, ``2017`` is short for
    ``2017-01-01T00:00:00+00:00``.
    ''',
    'FIELD VALUES...': '''Specifies an 'in' query where FIELD is a property
    of the item-type and VALUES is space or comma separated text or numbers.
    ''',
    'GEOM': '''Specify a geometry in GeoJSON format either as an inline value,
    stdin, or a file. ``@-`` specifies stdin and ``@filename`` specifies
    reading from a file named 'filename'. Otherwise, the value is assumed to
    be GeoJSON.
    ''',
    'FILTER': '''Specify a Data API search filter provided as JSON.
    ``@-`` specifies stdin and ``@filename`` specifies reading from a file
    named 'filename'. Otherwise, the value is assumed to be JSON.
    ''',
    'ITEM-TYPE': '''Specify Item-Type(s) of interest. Case-insensitive,
    supports glob-matching, e.g. ``psscene*`` means ``PSScene``,
    ``PSScene3Band``, and ``PSScene4Band``. The ``all`` value specifies
    every Item-Type.
    ''',
    'ASSET-TYPE': '''Specify Asset-Type(s) of interest. Case-insenstive,
    supports glob-matching, e.g. ``visual*`` specifies ``visual`` and
    ``visual_xml``.
    '''
}


class _LenientChoice(click.Choice):
    '''Like click.Choice but allows
    case-insensitive prefix matching
    optional 'all' matching
    optional prefix matching
    glob matching
    format fail msges for large selection of choices

    returns a list unlike choice (to support 'all')
    '''

    allow_all = False
    allow_prefix = False

    def get_metavar(self, param):
        return self.name.upper()

    def _fail(self, msg, val, param, ctx):
        self.fail('%s choice: %s.\nChoose from:\n\t%s' %
                  (msg, val, '\n\t'.join(self.choices)), param, ctx)

    def convert(self, val, param, ctx):
        matched = set()
        for p in _split(val):
            matched = matched.union(self._match(p, param, ctx))
        return list(matched)

    def _match(self, val, param, ctx, update_on_fail=True):
        lval = val.lower()
        if lval == 'all' and self.allow_all:
            return self.choices
        if '*' in lval:
            pat = lval.replace('*', '.*')
            matches = [c for c in self.choices
                       if re.match(pat, c.lower())]
        elif self.allow_prefix:
            matches = [c for c in self.choices
                       if c.lower().startswith(lval)]
        else:
            matches = [c for c in self.choices if c.lower() == lval]
        if not matches and update_on_fail:
            self._update_choices()  # get choices from a remote source.
            return self._match(val, param, ctx, False)  # Try one more time
        elif not matches:
            self._fail('invalid', val, param, ctx)
        else:
            return matches

    def _update_choices(self):
        self.choices = self.get_remote_choices()

    def get_remote_choices(self):
        '''
        No-op just returns current choices.
        Subclasses should override.
        '''
        return self.choices


class Bundle(_LenientChoice):
    name = 'bundle'
    allow_all = True

    def __init__(self):
        _LenientChoice.__init__(self, DEFAULT_BUNDLES)

    def get_remote_choices(self):

        return get_bundles()