function varargout = wfBrowser(varargin)
% wfBrowser is an interactive tool for exploring seismic data from a given 
% event. The interactive figure produced shows two maps, one centered on 
% event epicenter and one on the antipode. The event epicenter and stations 
% for which there is data are plotted on the map. To plot the data for any
% given station simply click on the station. The selected station will be
% highlighted in red and the seismic trace corresponding to that
% station will be plotted an annotated with the station name.
% 
% Usage:    wfBrowser(traces,eventData)
%           wfBrowser(traces,eventData,colorby)    
% 
% Description of inputs:
% 
% traces: this should be an array of structures containing the waveforms 
% and associated metadata. The structures should be arranged as what is 
% produced by irisFetch. Please refer to the irisFetch documentation for a 
% description of the fields. Fields that are required are: data, station, 
% latitude, longitude, sensitivity, sensitivityUnits, sampleCount, 
% sampleRate.
% 
% eventData: This is a structure containing elementary information
% about the event. Its fields should be:
%           lat: event latitude in degrees.
%           lon: event longitude in degrees.
%           depth: event depth in km.
% 
% clorby: This is the only input argument that is not required. colorby
% should be a 1x1 structure containing an arbitrary number of fields 
% defined by the user. Each field corresponds to an attribute, and field 
% names should be descriptive, as they will appear in a drop-down menu that
% allows the user to select between them. Each field should contain a 1xN 
% (or Nx1) vector - where N is the number of traces - containing the 
% attribute values for each trace.

% WFBROWSER M-file for wfBrowser.fig
%      WFBROWSER, by itself, creates a new WFBROWSER or raises the existing
%      singleton*.
%
%      H = WFBROWSER returns the handle to a new WFBROWSER or the handle to
%      the existing singleton*.
%
%      WFBROWSER('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in WFBROWSER.M with the given input arguments.
%
%      WFBROWSER('Property','Value',...) creates a new WFBROWSER or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before wfBrowser_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to wfBrowser_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help wfBrowser

% Last Modified by GUIDE v2.5 08-Aug-2013 11:01:57

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @wfBrowser_OpeningFcn, ...
                   'gui_OutputFcn',  @wfBrowser_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before wfBrowser is made visible.
function wfBrowser_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to wfBrowser (see VARARGIN)

% Choose default command line output for wfBrowser
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes wfBrowser wait for user response (see UIRESUME)
% uiwait(handles.figure1);

% Get the variables out of varargin

set(gcf,'menu','figure')

traces = varargin{1};
eventData = varargin{2};
tf_color=false;
set(handles.cb_ax,'visible','off')

if length(varargin) < 3
    set(handles.color_pup,'enable','off')
else
    colorby=varargin{3};
    set(handles.color_pup,'string',fieldnames(colorby))
    tf_color=true;
    set(handles.cb_ax,'visible','on')
end


%set the colormap
colormap 'jet'
CM=colormap;
colormap(flipud(CM(3:end-3,:)))

% set the window start and length to 0 and maximum length respectively:
set(handles.start_etxt,'string','0');

sC=[traces.sampleCount];
sR=[traces.sampleRate];
maxLength=max(sC./sR);
lengthString=num2str(maxLength);
set(handles.length_etxt,'string',lengthString);

%some things needed for plotting:

%calculate the great circle distance from the stations to the events (delta):
[theDeltas, ~]=distance(eventData.lat,eventData.lon,[traces.latitude],[traces.longitude]);


%find out which stations should be plotted on the antipode-centered map:
isAntipodal = (theDeltas >= 90);
k=1:length(traces); k=k'; %make it a column vector because h will be a column 
%vector and they need to be the same sixe in order to use arrayfun


%Dealing with the station names:
%this stores all the station names in a character matrix, which makes it
%easy to plot them later in a single call to 'text'
stationNames=char({traces.station}');
%now put a space before each name so it doesn't plot right on the symbol.
lSpace='   ';
leadingSpace=repmat(lSpace,[size(stationNames,1),1]);
stationNames=[leadingSpace stationNames];

%global map
subplot(handles.tele_ax)

axesm('ortho','Origin',[eventData.lat eventData.lon]); hold on
angles=linspace(0,360,3600);
plot(cosd(angles),sind(angles),'k-','LineWidth',2)

[stationX,stationY]=mfwdtran([traces.latitude],[traces.longitude]);

c=load('coast');
geoshow(c.lat,c.long,'DisplayType','Line','Color','k')
geoshow(eventData.lat,eventData.lon,'DisplayType','Point','Marker','p','MarkerEdgeColor','k','MarkerFaceColor','r','MarkerSize',14)


h=text(stationX(~isAntipodal),stationY(~isAntipodal),stationNames(~isAntipodal,:));
set(h,'tag','stationName')

h=plot([stationX(~isAntipodal);stationX(~isAntipodal)],[stationY(~isAntipodal); stationY(~isAntipodal)],...
    'ko','MarkerFaceColor',[.3 .3 .3],'MarkerSize',10);

set(h,'ButtonDownFcn',@showit)
arrayfun(@(hndl,num)(set(hndl,'UserData',num,'Tag','station')), h, k(~isAntipodal));

h=plot([stationX(~isAntipodal);stationX(~isAntipodal)],[stationY(~isAntipodal); stationY(~isAntipodal)],...
    'ro','MarkerFaceColor','none','MarkerSize',10,'LineWidth',4);
arrayfun(@(hndl,num)(set(hndl,'UserData',num+5000,'Visible','off','Tag','HL')), h, k(~isAntipodal));

%antipodal map
subplot(handles.anti_ax)

axesm('ortho','Origin',[-eventData.lat eventData.lon+180]); hold on
angles=linspace(0,360,3600);
plot(cosd(angles),sind(angles),'k-','LineWidth',2)

c=load('coast');
geoshow(c.lat,c.long,'DisplayType','Line','Color','k')

[stationX,stationY]=mfwdtran([traces.latitude],[traces.longitude]);

h=text(stationX(isAntipodal),stationY(isAntipodal),stationNames(isAntipodal,:));
set(h,'tag','stationName')

h=plot([stationX(isAntipodal);stationX(isAntipodal)],[stationY(isAntipodal); stationY(isAntipodal)],...
    'ko','MarkerFaceColor',[.3 .3 .3],'MarkerSize',10);
set(h,'ButtonDownFcn',@showit)
arrayfun(@(hndl,num)(set(hndl,'UserData',num,'Tag','station')), h, k(isAntipodal));


h=plot([stationX(isAntipodal);stationX(isAntipodal)],[stationY(isAntipodal); stationY(isAntipodal)],...
    'ro','MarkerFaceColor','none','MarkerSize',10,'LineWidth',4);
arrayfun(@(hndl,num)(set(hndl,'UserData',num+5000,'Visible','off','Tag','HL')), h, k(isAntipodal));

set(findobj('tag','stationName'),'Visible','off','Clipping','on')

if tf_color
    colorPoints(colorby);
    setappdata(gcf,'colorby',colorby)
    
end

% save some variables where they can be accessed by functions later.
setappdata(gcf,'traces',traces)



% --- This function fills in the colors of the stations.
function colorPoints(colorby)
% Property used for colors:
handles=guihandles(gcf);
cList = fieldnames(colorby);
cSelected = get(handles.color_pup,'Value');

%these are the values used to color the symbols
cValues=colorby.(cList{cSelected});

minVal = min(cValues);
maxVal = max(cValues);

cScale = colormap;
nColors = length(cScale); %number of colors in the colormap

%loop through and assign a color to each station.
for k=1:length(cValues)
    
    cix = 1 + round( (nColors-1) *  (cValues(k)-minVal)/(maxVal-minVal) );
    mfc = cScale(cix,:);
    h=findobj('UserData',k);
    set(h,'MarkerFaceColor',mfc);
    
end


subplot(handles.cb_ax)
h=colorbar;
caxis([minVal maxVal])
p=get(handles.cb_ax,'position');
u=get(handles.cb_ax,'units');
set(h,'units',u,'position',p);
set(handles.cb_ax,'xtick',[],'ytick',[],'visible','off')





% --- Outputs from this function are returned to the command line.
function varargout = wfBrowser_OutputFcn(hObject, eventdata, handles) 
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;


% --- Executes on button press in ppts_btn.
function ppts_btn_Callback(hObject, eventdata, handles)
% hObject    handle to ppts_btn (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

set(findobj('Tag','HL'),'Visible','off')

xsh=getappdata(gcf,'xsh');
delete(xsh(ishandle(xsh)))

setappdata(gcf,'xs_pt_1',[])
setappdata(gcf,'xs_pt_2',[])
cla(handles.spec_ax)
set(gcf,'Pointer','cross'); drawnow
set(handles.tele_ax,'ButtonDownFcn',@xsc_pts)
set(handles.anti_ax,'ButtonDownFcn',@xsc_pts)


% --- Executes on button press in xsect_btn.
function xsect_btn_Callback(hObject, eventdata, handles)
% hObject    handle to xsect_btn (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)



function mxd_etxt_Callback(hObject, eventdata, handles)
% hObject    handle to mxd_etxt (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of mxd_etxt as text
%        str2double(get(hObject,'String')) returns contents of mxd_etxt as a double


% --- Executes during object creation, after setting all properties.
function mxd_etxt_CreateFcn(hObject, eventdata, handles)
% hObject    handle to mxd_etxt (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end





function [x] = showit(varargin)

if nargin == 1
    k=varargin{1};
else
    k=get(varargin{1},'UserData');
end

xsh=getappdata(gcf,'xsh');
delete(xsh(ishandle(xsh)))

set(findobj('Tag','HL'),'Visible','off')
set(findobj('UserData',5000+k),'Visible','on')

handles=guihandles(gcf);

traces=getappdata(gcf,'traces');
thisTrace=detrend(traces(k).data);
thisTrace=thisTrace/traces(k).sensitivity;

traceTime=linspace(0,(traces(k).sampleCount-1)/traces(k).sampleRate,traces(k).sampleCount);

subplot(handles.spec_ax); 
cla; hold on; 
set(gca,'Ydir','normal'); % in case plotting a record section reversed it.


plot(traceTime,thisTrace,'LineWidth',2)

windowStart=str2double(get(handles.start_etxt,'string'));
windowLength=str2double(get(handles.length_etxt,'string'));

ylabel(traces(k).sensitivityUnits,'FontSize',14)
xlabel('seconds','FontSize',14)


ix=(traceTime >= windowStart & traceTime <= windowStart+windowLength);
maxAmp=double(max(abs(thisTrace(ix)))); %maxAmp is the maximum amplitude in the plotting window

%write the name of the station on the waveform plot
text(windowStart+(windowLength*.05),.8*maxAmp,traces(k).station,'FontWeight','bold','FontSize',14);

ylim([-1.1 1.1]*maxAmp)
xlim([0 windowLength]+windowStart)

grid on
set(gca,'FontSize',14)



function [pt1 pt2] = xsc_pts(src,evt)

handles=guihandles(gcf);

h=getappdata(gcf,'xsh');

p1=getappdata(gcf,'xs_pt_1');

mh = [handles.tele_ax; handles.anti_ax];

A = get(gca,'CurrentPoint');
x=A(1,1); y=A(1,2);

[lat,lon] = minvtran(x, y );

if isempty(p1)
    p1 = [ lat lon];
    h(1)=plot(x,y,'k+','LineWidth',4,'Color','k');
    setappdata(gcf,'xs_pt_1',p1)
else
    p2 = [ lat lon];

    h(2)=plot(x,y,'k+','LineWidth',4,'Color','k');
    [x1,y1] = mfwdtran(p1(1), p1(2) );
    h(3)=plot([x1 x],[y1 y],'--','LineWidth',2,'Color','k');
    setappdata(gcf,'xs_pt_2',p2)
    set(mh,'ButtonDownFcn','')
    set(gcf,'Pointer','arrow')
    drawnow
    
    [rng az]=distance(p1, p2);
    
    mstruct=defaultm('mercator');

    mstruct.origin=[p1(1) p1(2) -(az-90)];
    mstruct.scalefactor=6371;
    mstruct=defaultm(mstruct);
    
    [xx2 yy2]=mfwdtran(mstruct,p2(1),p2(2)); 
    %xx2 yy2 are the coordinates in the mercator projection of the second
    %profile endpoint.
    
    traces=getappdata(gcf,'traces');
    xsta=nan(length({traces.station}),1); ysta=xsta;
    for k = 1:length({traces.station}) 
        [xsta(k) ysta(k)] = mfwdtran(mstruct,traces(k).latitude,traces(k).longitude);
    end
    
    ymax=str2double(get(handles.mxd_etxt,'String'));
    
    stix=find(abs(ysta) < ymax & xsta > 0 & xsta < xx2);
    %stix are the indexes to the stations that should be plotted in the
    %profile.
    
    for k=1:length(stix)
    hiliteh=findobj('UserData',5000+stix(k));
    set(hiliteh,'Visible','on');
    end
    
    plotTraces = traces(stix);
    
    %this for loop preconditions each trace to be plotted
    for k=1:length(plotTraces)
        thisTrace=plotTraces(k).data;
        thisTrace=detrend(thisTrace);
        thisTrace=thisTrace/max(abs(thisTrace));
        plotTraces(k).data=thisTrace;
        plotTraces(k).time=linspace(0,(plotTraces(k).sampleCount-1)/plotTraces(k).sampleRate,plotTraces(k).sampleCount);
    end
    
    xdists = xsta(stix);
    aNumber=12; %make this number larger for narrower traces, smaller for wider.
    sFactor = xx2/aNumber; sFactor=sFactor/2; %space between traces?
    
    subplot(handles.spec_ax); cla; hold on
    
    for k=1:length(xdists)
        t=ones(length(plotTraces(k).data),1);
        plot(t*xdists(k)+sFactor*plotTraces(k).data , plotTraces(k).time ,'b-')
    end
    
    
    windowStart=str2double(get(handles.start_etxt,'string'));
    windowLength=str2double(get(handles.length_etxt,'string'));
    
    set(gca,'Ydir','reverse');  
    ylim([0 windowLength]+windowStart)
    ylabel('time (s)')
    
    %sets x limit from zero to the end of the profile.
    xlim([0 xx2])
    xlabel('distance (km)')
    
    grid on
    box on

end

setappdata(gcf,'xsh',h)



function gto_sta_etxt_Callback(hObject, eventdata, handles)
% hObject    handle to gto_sta_etxt (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of gto_sta_etxt as text
%        str2double(get(hObject,'String')) returns contents of gto_sta_etxt as a double


% --- Executes during object creation, after setting all properties.
function gto_sta_etxt_CreateFcn(hObject, eventdata, handles)
% hObject    handle to gto_sta_etxt (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on key press with focus on gto_sta_etxt and none of its controls.
function gto_sta_etxt_KeyPressFcn(hObject, eventdata, handles)
% hObject    handle to gto_sta_etxt (see GCBO)
% eventdata  structure with the following fields (see UICONTROL)
%	Key: name of the key that was pressed, in lower case
%	Character: character interpretation of the key(s) that was pressed
%	Modifier: name(s) of the modifier key(s) (i.e., control, shift) pressed
% handles    structure with handles and user data (see GUIDATA)

flg=get(handles.gto_sta_etxt,'UserData');

if strcmp(eventdata.Key ,'return')
    if flg==0; flg=1;
    else
        theStation=get(handles.gto_sta_etxt,'String');
        
        traces=getappdata(gcf,'traces');
        
        stationNames={traces.station};
        
        ix=find(strcmp(theStation,stationNames));
        ix=ix(1); %this in case the station is repeated.
        
        if isempty(ix);
            disp('No stations by that name')
        else
            showit(ix)
        end
        
        flg=0;
    end
end

set(handles.gto_sta_etxt,'UserData',flg);



% --- Executes on selection change in color_pup.
function color_pup_Callback(hObject, eventdata, handles)
% hObject    handle to color_pup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns color_pup contents as cell array
%        contents{get(hObject,'Value')} returns selected item from color_pup
colorby = getappdata(gcf,'colorby');
colorPoints(colorby)


% --- Executes during object creation, after setting all properties.
function color_pup_CreateFcn(hObject, eventdata, handles)
% hObject    handle to color_pup (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function start_etxt_Callback(hObject, eventdata, handles)
% hObject    handle to start_etxt (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of start_etxt as text
%        str2double(get(hObject,'String')) returns contents of start_etxt as a double


% --- Executes during object creation, after setting all properties.
function start_etxt_CreateFcn(hObject, eventdata, handles)
% hObject    handle to start_etxt (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end



function length_etxt_Callback(hObject, eventdata, handles)
% hObject    handle to length_etxt (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of length_etxt as text
%        str2double(get(hObject,'String')) returns contents of length_etxt as a double


% --- Executes during object creation, after setting all properties.
function length_etxt_CreateFcn(hObject, eventdata, handles)
% hObject    handle to length_etxt (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in staNames_chk.
function staNames_chk_Callback(hObject, eventdata, handles)
% hObject    handle to staNames_chk (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of staNames_chk

if get(hObject,'Value')
set(findobj('tag','stationName'),'visible','on')
else
set(findobj('tag','stationName'),'visible','off')
end
