1from logging import error
  2from django.http import JsonResponse, HttpResponseBadRequest
  3
  4import chart
  5
  6from chart.db.model.exceptions import NoSuchTable
  7from chart.db.model.table import find_param_by_name
  8from chart.db.model.table import TableInfo
  9from chart.project import SID
 10from chart.project import settings
 11
 12from chart_rest.response_builder import single_linear
 13from chart_rest.response_builder import correlation
 14from chart_rest.response_builder import limits
 15from chart_rest.response_builder import histogram
 16from chart_rest.response_builder import csv
 17from chart_rest.response_builder import bit_histogram
 18from chart_rest.response_builder import textual_bar
 19from chart_rest.response_builder import build_pspec
 20from chart_rest.response_builder import geolocation_map
 21from chart_rest.tree import build_events_tree
 22from chart_rest.tree import build_table_tree
 23from chart_rest.tree import build_main_tree
 24from chart_rest.search import do_search
 25
 26from chart.plotviewer.plot_utils import PlotException
 27from chart.plotviewer.plot_utils import PlotType
 28
 29# API Version for info endpoint
 30API_VERSION = 0.1
 31
 32SID() # load all chart config
 33
 34
 35def timeseries(request):
 36    """
 37    Handle timeseries request
 38    """
 39    try:
 40        pspec = build_pspec(request)
 41
 42        # Create default plot
 43        if pspec['ptype'] in (
 44            PlotType.AUTO, PlotType.LINE,
 45            PlotType.MINMAX, PlotType.BAR_O,
 46            PlotType.BAR_S, PlotType.COVERAGE,
 47            PlotType.GEO
 48        ):
 49            return JsonResponse(single_linear(pspec))
 50        elif pspec['ptype'] is PlotType.GANTT:
 51            return JsonResponse(textual_bar(pspec))
 52        elif pspec['ptype'] is PlotType.CORRELATION:
 53            correlation = correlation(pspec)
 54
 55            if correlation is None:
 56                return JsonResponse(
 57                    {
 58                        "status": False,
 59                        "message": "No data found for time range"
 60                    }, status=404)
 61            else:
 62                return JsonResponse(correlation)
 63
 64        # Create limits plot
 65        elif pspec['ptype'] is PlotType.LIMITS:
 66            return JsonResponse(limits(pspec))
 67
 68        # Create histogram plot
 69        elif pspec['ptype'] is PlotType.HISTO:
 70            min_val = None
 71            max_val = None
 72            log_val = False
 73            if len(pspec.get('axes', [])) >= 1:
 74                ax = pspec['axes'][0]
 75                min_val = ax.get('min')
 76                max_val = ax.get('max')
 77                log_val = ax.get('log', False)
 78
 79            hist = histogram(
 80                             pspec,
 81                             min_val=min_val,
 82                             max_val=max_val,
 83                             logscale=log_val
 84                            )
 85
 86            return JsonResponse(hist)
 87
 88        # Create bit histogram plot
 89        elif pspec['ptype'] is PlotType.BITS:
 90            return JsonResponse(bit_histogram(pspec))
 91
 92        # Return data for CSV export
 93        elif pspec['ptype'] is PlotType.CSV:
 94            return JsonResponse(csv(pspec))
 95
 96    except PlotException as e:
 97        return JsonResponse(
 98            {
 99                "status": False,
100                "message": str(e)
101            }, status=500
102        )
103
104
105def info(request):
106    """
107    Handle domain info request
108    """
109
110    project_version = "N/A"
111    try:
112        project_version = settings.VERSION
113    except AttributeError:
114        ver = chart.project_version()
115        project_version = ver if ver is not None else "N/A"
116
117    chart_core_version = "N/A"
118    try:
119        chart_core_version = chart.__version__
120    except AttributeError:
121        ver = chart.version()
122        chart_core_version = ver if ver is not None else "N/A"
123
124    regions = []
125    try:
126        for s in SID.sampling_options: 
127            regions.append(s.region)
128    except:
129        regions = SID.sampling_options()
130
131    return JsonResponse({
132        'project_version': project_version,
133        'core_version': chart_core_version,
134        'api_version': API_VERSION,
135        'stats': ['MIN', 'MAX', 'AVG', 'STD'], # These are hard-coded as in api2
136        'regions': regions,
137        'tables': sorted([t.name for t in TableInfo.all()]),
138    })
139
140
141def tables(request):
142    """
143    Handle table request
144    """
145
146    if "table" in request.GET:
147        # Return information about a single table."""
148        try:
149            table_info = TableInfo(request.GET['table'])
150
151            return JsonResponse(
152                {'name': table_info.name,
153                'description': table_info.description,
154                'has_stats': table_info.has_stats,
155                'common_fields': ['SENSING_TIME'],
156                'fields': [f for f in sorted(table_info.fields.keys())],
157                })
158        except NoSuchTable:
159            return JsonResponse({"status": False, "message": "Table not found"}, status=404)
160
161    else:
162        return JsonResponse({
163            'tables': sorted([t.name for t in TableInfo.all()]),
164        })
165
166def parameter(request):
167    """
168    Handle parameter metadata request
169    """
170
171    table_name = None
172    field_name = None
173    if "parameter" in request.GET:
174        parts = request.GET["parameter"].split(".")
175        if len(parts) == 2:
176            table_name = parts[0]
177            field_name = parts[1]
178
179    if table_name == None or field_name == None:
180        return  JsonResponse({"status": False, "message": "Define parameter as table.field"}, status=400)
181
182    field_info = find_param_by_name(field=field_name, table=table_name)
183
184    if field_info:
185        choices = None
186        if field_info.choices != None:
187            choices = field_info.choices.items
188
189        return JsonResponse(
190            {
191                "name": field_info.name,
192                "description": field_info.description,
193                "unit": field_info.unit,
194                "datatype": field_info.datatype.name,
195                "calibration_name": field_info.calibration_name,
196                "choices":  choices
197            })
198    else:
199        return JsonResponse({"status": False, "message": "Parameter not found"}, status=404)
200
201def tree(request):
202    """
203    Handle parameter tree request
204
205    Returns either table, events or main tree
206    """
207
208    table = None
209    sid_name = None
210    if "key" in request.GET:
211        table = request.GET["key"].split(".")[0]
212    if "sid" in request.GET:
213        sid_name = request.GET["sid"]
214
215    if table == "EVENTS":
216        res = build_events_tree()
217
218    elif table != None:
219        res = build_table_tree(table)
220
221    else:
222        res = build_main_tree(sid_name)
223
224    return JsonResponse(res)
225
226def search(request):
227    """
228    Search for events and parameters
229    based on any field, name, description or unit
230    """
231    any_field, name, description, unit, source = None, None, None, None, None
232
233    if "any" in request.GET:
234        any_field = request.GET["any"]
235    if "name" in request.GET:
236        name = request.GET["name"]
237    if "description" in request.GET:
238        description = request.GET["description"]
239    if "unit" in request.GET:
240        unit = request.GET["unit"]
241    if "source" in request.GET:
242        source = request.GET["source"]
243    if "sid" in request.GET:
244        sid_name = request.GET["sid"]
245
246    results = do_search(
247        any_field=any_field,
248        name=name,
249        description=description,
250        unit=unit,
251        source=source,
252        sid_name=sid_name)
253
254    return JsonResponse({"tree": results})
255
256def geolocation(request):
257    """
258    Get spacecraft latitude/longitude coordinates
259    """
260    pspec = build_pspec(request)
261
262    data = geolocation_map(pspec)
263
264    return JsonResponse(data)